9

我是泛型的新手,所以不知道我要去哪里错了......

我有名为 Cat、Dog 和 Rabbit 的类,它们实现了接口 Animal。

以下代码将编译

Set<? extends Animal> animalSet;
Set<Dog> dogSet = new HashSet<Dog>();
animalSet = dogSet;

但是下面的代码不会

Map<String, Set<? extends Animal>> animalMap;
Map<String, Set<Dog>> dogMap = new HashMap<String, Set<Dog>>();
animalMap = dogMap; // this line will not compile

编译器说类型不兼容。我哪里错了?

更新

感谢大家的帮助

我通过添加另一个通配符更改了第一行代码以下代码将编译

Map<String, ? extends Set<? extends Animal>> animalMap;
Map<String, Set<Dog>> dogMap = new HashMap<String, Set<Dog>>();
animalMap = dogMap;

另请参阅下面 Cyrille Ka 给出的解决方案 - 使用 putAll() 将值从 dogMap 传输到 animalMap,而不是将 dogMap 分配给 animalMap。

4

7 回答 7

7

基本上,当你写:

Map<String, Set<? extends Animal>> animalMap;

您声明地图的任何值都是一个集合,该集合可以包含任何类型为 Animal 子类的对象。那么客户端代码编写是完全合理的:

animalMap.put("miaow", aCatSet);

哪里acatSetSet<Cat>

dogMap不能接受 aSet<Cat>作为值,它只能接受Set<Dog>。因此存在类型不兼容的可能性,这就是禁止这种构造的原因。

编辑:至于如何解决这个问题,这取决于你想做什么。如果您有dogMap某个地方并想将其内容放入其中animalMap,则可以像这样简单地复制内容:

Map<String, Set<? extends Animal>> animalMap = new HashMap<String, Set<? extends Animal>>();
Map<String, Set<Dog>> dogMap = new HashMap<String, Set<Dog>>();

/// fill dogMap

animalMap.putAll(dogMap);
于 2013-11-07T15:11:48.103 回答
3

因为 Java 是强类型的:? extends Animalis not Dog,它可能是Cat,或另一个子类。

例如,在这种情况下,如果你定义Set<? extends Animal> animalSet,我可以合法地做animalSet.add(new Cat()),对吧?但是你想animalSet用 a来初始化它Set<Dog>,这不再允许animalSet.add(new Cat())了。这是不一致的,这就是不允许的原因。

于 2013-11-07T15:08:21.670 回答
2

解决您的问题的方法是:

Map<String, ? extends Set<? extends Animal>> animalMap;
Map<String, Set<Dog>> dogMap = new HashMap<String, Set<Dog>>();
animalMap = dogMap;

因为Set<Dog>不是 a Set<? extends Animal>,而是扩展它。

于 2013-11-07T15:59:12.023 回答
1

将以下逻辑(基于此答案)应用于您的问题:

  • Dog Animal
  • Set<Dog> Set<? extends Animal>
  • Map<String, Dog> 不是 Map<String, Animal>

所以 :

  • Map<String, Set<Dog>> 不是 Map<String, Set<? extends Animal>>

这就是编译器在您上一次作业中抱怨的内容。

于 2013-11-07T15:40:41.923 回答
1

至于为什么——让我稍后再说。现在请注意,这会编译:

Map<String, Set<? extends Animal>> animalMap;
Map<String, Set<? extends Animal>> dogMap 
    = new HashMap<String, Set<? extends Animal>>();
Set<Dog> dogMapVal = new HashSet<Dog>();
dogMap.put("fido", dogMapVal);
animalMap = dogMap; 
于 2013-11-07T15:07:59.343 回答
0

这里父子关系不像 Parent p = child 那样工作。甲骨文文档

于 2013-11-07T15:09:58.133 回答
0

因为 Dog 不等于 Animal,只是扩展它。

图片,如果有一个代码,你在某个地方使用这个代码,你把狗放进去。之后,又某处你想再次使用它,你认为你把狗放在这里,所以你把狗带回来了。但如果有人,把猫或兔子放在上面?

所以这就是为什么。

于 2013-11-07T15:10:45.187 回答