我有一个使用通配符的List
,如下所示:
List<DataLink<? extends Context>> dataLinks = new ArrayList<>();
dataLinks.add(new ContextDataLink());
dataLinks.add(new SomeOtherContextDataLink());
我希望能够遍历此
List
并在每个元素上调用retrieve
方法:Context context = new SomeOtherContext();
for(DataLink<? extends Context> dataLink : dataLinks) {
System.out.println(dataLink.retrieve(context));
}
但是,我在
println
语句中收到以下编译器错误:类型为
retrieve(capture#3-of ? extends Context)
的方法>DataLink<capture#3-of ? extends Context>
不适用于参数> (Context)
有没有办法实现上述目标?它不一定必须使用泛型,但我认为使用泛型将使我能够防止显式强制转换
我对SO进行了一些解答,并了解了为什么会发生此错误。但是,我找不到解决方案。我知道我可以编写一种捕获通配符的方法,但这似乎也不能解决问题:
public static <T extends Context> void retrieve(List<DataLink<T>>
dataLinks,T context) {
for(DataLink<T> dataLink : dataLinks) {
dataLink.retrieve(context);
}
}
当我调用上述检索方法时,出现以下编译错误:
MyClass类型的方法
retrieve(List<DataLink<T>>, T)
不适用于参数> (List<DataLink<? extends Context>>, Context)
以下是
Context
,SomeOtherContext
,DataLink
实现的定义: static class Context {
public String doContextThings() {
return "contextThings";
}
}
static class SomeOtherContext extends Context {
public String doSomeOtherContextThings() {
return "someOtherContextThings";
}
}
interface DataLink<T extends Context> {
public String retrieve(T context);
}
static class ContextDataLink implements DataLink<Context> {
@Override
public String retrieve(Context context) {
return context.doContextThings();
}
}
static class SomeOtherContextDataLink implements
DataLink<SomeOtherContext> {
@Override
public String retrieve(SomeOtherContext context) {
return context.doSomeOtherContextThings();
}
}
注意:不涉及泛型的解决方案是最直接的解决方案,其中将
DataLink
类修改为不采用类型参数,而始终将Context
作为retrieve
方法的参数类型。在这里,子类会将Context
强制转换为他们期望的任何类型。但是,问题仍然存在。在这种情况下,这是被认为是不良设计还是可以接受的? 最佳答案
根本问题是您想给retrieve
方法一个不支持的参数。例如,列表中的元素之一可能是DataLink<ContextA>
,并且您想在其上调用retrieve(ContextB)
。
您需要编写一些代码来确定处理方式。
如果将代码放在retrieve
方法实现中,则可以将任何类型的上下文传递给任何retrieve
方法,并且可以声明它采用简单的Context
参数。然后,每个实现都可以对传递给它的上下文进行instanceof
检查,并决定如何处理它。
这样,就不需要定义DataLink
方法的retrieve
类上的type参数,但是您仍然可以将其包含在该类上,并根据需要将其用于其他用途。