不兼容的类型:捕获?延伸...不可转换为捕获?扩展

时间:2018-05-16 22:12:48

标签: java generics

我在对象中有一个变量:

private final Map<Long, ? extends MovieInfoDTO> bElementsToAdd = new HashMap<>();

使用Builder模式中的方法我想完成此地图。

public Builder withElementsToAdd(@Nullable final Map<Long, ? extends MovieInfoDTO> elementsToAdd) {
     this.bElementsToAdd.clear();
     if(elementsToAdd != null) {
         this.bElementsToAdd.putAll(elementsToAdd);
     }
     return this;
}

但是,我收到错误。

    putAll
(java.util.Map<? extends java.lang.Long,? extends capture<? extends com.jonki.popcorn.common.dto.movie.MovieInfoDTO>>)
in Map cannot be applied
to
(java.util.Map<java.lang.Long,capture<? extends com.jonki.popcorn.common.dto.movie.MovieInfoDTO>>)

如何更正这种补充地图的方法?

2 个答案:

答案 0 :(得分:1)

当您在bElementsToAdd的声明中放置上限通配符时,编译器不知道您在那里MovieInfoDTO的哪个子类型。理论上,您可以合法地将Map<Long, MovieInfoSubclassDTO>MovieInfoSubclassDTO作为MovieInfoDTO的理论子类)分配给bElementsToAdd

方法putAll应该能够将来自另一个地图的所有映射放入原始地图中。它的类型可以高达Map<Long, MovieInfoDTO>。变量bElementsToAdd必须能够接受MovieInfoDTO作为键。

解决方案:删除bElementsToAdd上的通配符上限。

private final Map<Long, MovieInfoDTO> bElementsToAdd = new HashMap<>();

您无需删除elementsToAdd上的上限通配符(withElementsToAdd的参数),您不应将其删除。保留上限通配符允许调用代码传递Map<Long, MovieInfoSubclassDTO>,这是可以接受的,因为类型MovieInfoSubclassDTOMovieInfoDTO的理论子类)应该被允许作为bElementsToAdd中的值1}}。

答案 1 :(得分:1)

简短回答:您无法为具有该类型的地图添加值。根据经验,您可以阅读? extends作为&#34;只读&#34;,因此您的地图是&#34;只读&#34; MovieInfoDTO个对象。

更长的回答:? extends T有点奇怪;当你正在运行时,类型检查器会将类型? extends T的不同语法出现表达式视为不同,不兼容&#34;捕获&#34;不要键入检查彼此相等。因此bElementsToAdd类型为Map<Long, ? extends MovieInfoDTO>,因此bElementsToAdd.put()采用新值&#34;捕获&#34; ? extends MovieInfoDTO。但是没有办法获得同样的捕获!即使您执行了bElementsToAdd.put(k, bElementsToAdd.get(k))putget也会使用不同的捕获,因此它们不是兼容的类型!

您显然没有想要只读地图,因为您正在尝试更新它。所以,你有几个选择。一种是删除通配符 - 如果你不关心你所拥有的MovieInfoDTO的哪个子类型是有意义的,你可以将它们混合在同一个地图中。如果你关心,那么你可能想要为整个地图添加一个界限:

class MyClass<T extends MovieInfoDTO> {
  // ... 
  private final Map<Long, T> bElementsToAdd = new HashMap<>();

  //...
  public Builder withElementsToAdd(@Nullable final Map<Long, T> elementsToAdd) {
   // ...
}

这会强制执行约束,即您在withElementsToAdd中添加的元素类型必须与地图中的元素类型相同,即使您并不关心究竟是哪种类型。