泛型 - 集合中的Java集合

时间:2013-11-07 15:00:27

标签: java generics collections nested

我是仿制药的新手,所以不确定我哪里出错......

我有一个名为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。

7 个答案:

答案 0 :(得分:7)

基本上,当你写:

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

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

animalMap.put("miaow", aCatSet);

其中acatSetSet<Cat>

dogMap无法接受Set<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);

答案 1 :(得分:3)

因为Java是强类型的:? extends Animal不是Dog,它可能是Cat或其他子类。

例如,在这种情况下,如果您定义Set<? extends Animal> animalSet,我可以合法地执行animalSet.add(new Cat()),对吧?但是您希望使用animalSet初始化此Set<Dog>,这将不再允许animalSet.add(new Cat())。这是不一致的,这就是不允许的原因。

答案 2 :(得分:2)

问题的解决方案是:

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

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

答案 3 :(得分: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; 

答案 4 :(得分:1)

将以下逻辑(基于this answer)应用于您的问题:

  • Dog IS Animal
  • Set<Dog> IS Set<? extends Animal>
  • Map<String, Dog> Map<String, Animal>

因此:

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

这就是编译器在你上一次任务中抱怨的内容。

答案 5 :(得分:0)

此处父子关系不起作用,如父p = child。 oracle docs

答案 6 :(得分:0)

因为狗不等于动物,只能扩展它。

图片,如果有代码,你在这个代码的某处使用,你把狗放在里面。之后,你又想再次使用它,你认为你把狗放在这里,所以你回来了。但是,如果有人,将猫或兔子放入其中?

所以这就是原因。