我有一个使用通配符的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)


以下是ContextSomeOtherContextDataLink实现的定义:

 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参数,但是您仍然可以将其包含在该类上,并根据需要将其用于其他用途。

09-30 14:32
查看更多