继承不适用于作为泛型类型传递

use*_*048 8 java oop generics

考虑我的自定义扩展hashmap:

public class CustomHashMap extends HashMap<String, Object> {
...
}
Run Code Online (Sandbox Code Playgroud)

为什么这不起作用,因为CustomHashMap是HashMap的子代?

Map<String, HashMap<String, Object>> customs = new LinkedHashMap<String, CustomHashMap>();
Run Code Online (Sandbox Code Playgroud)

但这有效:

Map<String, HashMap<String, Object>> customs = new LinkedHashMap();
Run Code Online (Sandbox Code Playgroud)

当将CustomHashMap添加(放入)customsMap 时,它也可以工作.

customs.put("test", new CustomHashMap());
Run Code Online (Sandbox Code Playgroud)

在初始化工作中没有指定泛型似乎很奇怪,但它没有.

Deb*_*kia 7

此声明无效

Map<String, HashMap<String, Object>> customs = new LinkedHashMap<String, CustomHashMap>();
Run Code Online (Sandbox Code Playgroud)

因为customs是类型Map<String, HashMap<String, Object>>而你正在分配一个LinkedHashMap类型<String, CustomHashMap>,其中CustomHashMap是一个子类HashMap<String, Object>.

泛型是invariant:对于任何两个不同的类型T1T2,HashMap<String, T1>既不是亚型也不的超类型HashMap<String, T2>.所以,LinkedHashMap<String, CustomHashMap>不能分配给Map<String, HashMap<String, Object>>.另一方面,数组是covariant,这意味着下面的语句将编译而没有任何错误或警告.但是,它可能会在运行时,如果你把任何其他亚型失败(这可能会造成更多的伤害)HashMap<String, Object>进入它除了CustomHashMap:

HashMap<String, Object>[] mapArray = new CustomHashMap[1];
mapArray[0] = new CustomHashMap_1();// this will throw java.lang.ArrayStoreException
Run Code Online (Sandbox Code Playgroud)

现在,如果你要分配LinkedHashMap<String, CustomHashMap>Map<String, HashMap<String, Object>>,该语句改成这样:

Map<String, ? extends HashMap<String, Object>> customs = new LinkedHashMap<String, CustomHashMap>();
Run Code Online (Sandbox Code Playgroud)

@Seelenvirtuose很好地解释了关于这种方法的一些额外信息,这是公认的答案.


See*_*ose 4

使用泛型时,您应该始终牢记类型擦除。在运行时,类型的对象Map不再知道其类型参数。结果:ALinkedHashMap<String, CustomHashMap>不是 的子类型Map<String, HashMap<String, Object>>

如果您想要与子类型相关的内容,则必须按以下方式进行:

Map<String, ? extends HashMap<String, Object>> customs = new LinkedHashMap<String, CustomHashMap>();
Run Code Online (Sandbox Code Playgroud)

这称为上限通配符,并且正是针对这种情况而存在:获取子类型关系。有关更多信息,请参阅有关泛型的 Java 教程。


根据评论的附加信息:

上限版本在如何使用海关地图方面存在缺点。您不能再将实例放入该地图中。唯一允许的值是null. 原因是,您可以扩展另一个类Map<String, HashMap>,并尝试将其实例放入您的海关地图中。但这是一个问题,因为变量 Customs 指的是使用 参数化的地图CustomHashMap

使用有界通配符时,您应该始终提醒PECS。PECS 代表“生产者扩展,消费者超级”。这对于方法参数很有价值。如果您编写一个只需要从此类映射中读取值的方法,则可以将参数键入为Map<String, ? extends Map<String, Object>>。这称为生产者。如果您只需要写入该映射,请使用关键字super。如果你两者都需要——读和写——那么你两者都不能做。

  • 请记住,通过该声明,您可以添加到“customs”的唯一值是 null,这是确保满足地图中使用的任何值类型的唯一值。 (2认同)
  • -1 类型擦除与泛型不协变的原因无关。 (2认同)