为什么带有泛型声明的HashMap"<?super ArrayList>不接受值"put方法中的新对象()"?

MKo*_*Kod 11 java generics wildcard hashmap superclass

在处理面试问题时,我遇到了以下代码:

List<Object> list = new ArrayList();
Map<Object, ? super ArrayList> m = new HashMap<Object,  ArrayList>();
m.put(1, new Object());
m.put(2, list);
Run Code Online (Sandbox Code Playgroud)

上面两个put方法都是抛出编译时错误.但是,当我添加m.put(3, new ArrayList());它时添加到map没有编译时错误.

我很清楚我可以添加new Object()一个值,HashMap因为map声明属于类型< ? super ArrayList>; 这意味着我可以补充一点,高于任何值ArrayList(即超级ArrayList)和ArrayList下面反对过,但没有什么ArrayList.

这个特殊的概念在Kathy Sierra和Bert Bates的SCJP 6中写得非常好,基于该理论和实例,我认为它应该按照我的理解工作.有人可以帮我理解错误吗?

Jes*_*per 8

你误解了通配符的?含义.你可能有一个常见的误解:

并不意味着你可以把任何类型的对象在地图这是一种类型,它的父类的ArrayList.

这意味着地图中的值属于某种类型的未知类型ArrayList.由于确切的类型是未知的,编译器将不允许您将除ArrayList自身之外的任何类型的值作为值添加到映射中 - 编译器没有足够的信息来检查您正在执行的操作是否是类型安全的.

假设这是允许的,那么你可以做这样的坏事:

Map<Object, ArrayList> m1 = new HashMap<Object, ArrayList>();

Map<Object, ? super ArrayList> m2 = m1;

// This should not be allowed, because m2 is really a HashMap<Object, ArrayList>
m2.put(1, new Object());
Run Code Online (Sandbox Code Playgroud)

  • (现在在计算机上)... super关键字有一个巨大的用例.查看Joshua Bloch的书"Effective Java(第2版)",他描述了PECS,它代表"Producer Extends,Consumer Super".这个SO答案可能有助于提供更多的洞察力:http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs (3认同)

Boh*_*ian 3

类型? super ArrayList表示未知类型,其下限为ArrayList。例如,它可能Object,但也可能是AbstractListArrayList

编译器唯一可以确定的是,该值的类型虽然未知,但保证不会比 更具体,因此可以添加ArrayList任何属于ArrayList或 的子类的对象。ArrayList

另请记住:编译器仅按照声明的类型进行处理;它忽略分配的类型。

为什么put(1, new Object())失败:

显然,Object不在界限之内。

为什么put(1, list)失败:

该变量的类型为List,它可能包含对 a 的引用LinkedList,但该引用不在所需的范围内。