我在对象中有一个变量:
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>>)
如何更正这种补充地图的方法?
答案 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>
,这是可以接受的,因为类型MovieInfoSubclassDTO
(MovieInfoDTO
的理论子类)应该被允许作为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))
,put
和get
也会使用不同的捕获,因此它们不是兼容的类型!
您显然没有想要只读地图,因为您正在尝试更新它。所以,你有几个选择。一种是删除通配符 - 如果你不关心你所拥有的MovieInfoDTO
的哪个子类型是有意义的,你可以将它们混合在同一个地图中。如果你做关心,那么你可能想要为整个地图添加一个界限:
class MyClass<T extends MovieInfoDTO> {
// ...
private final Map<Long, T> bElementsToAdd = new HashMap<>();
//...
public Builder withElementsToAdd(@Nullable final Map<Long, T> elementsToAdd) {
// ...
}
这会强制执行约束,即您在withElementsToAdd
中添加的元素类型必须与地图中的元素类型相同,即使您并不关心究竟是哪种类型。