List l = new ArrayList<Number>();
List<String> ls = l; // unchecked warning
l.add(0, new Integer(42)); // another unchecked warning
String s = ls.get(0); // ClassCastException is thrown
Run Code Online (Sandbox Code Playgroud)
java文档说;
此外,调用l.add方法时会发生堆污染情况.add方法的静态类型第二个形式参数是String,但是使用不同类型的实际参数Integer调用此方法.但是,编译器仍允许此方法调用.由于类型擦除,add方法的第二个形式参数的类型(定义为List.add(int,E))变为Object.因此,编译器允许此方法调用,因为在类型擦除之后,l.add方法可以添加任何Object类型的对象,包括Integer类型的对象
我的问题是关于我大胆的部分.据我所知,在第2行堆污染发生导致l引用List引用类型为List的对象.但是当调用add方法时,l引用不应该期望Number类型而不是String,因为l是对ArrayList的引用.或者是,在ls = l之后,堆中的空间List<String>
也是为了引用?在这种情况下,有意义的是java docs在粗体部分中所说的内容
但是当调用add方法时,l引用不应该期望Number类型而不是String,因为l是对ArrayList的引用.
List l
只是声明为无类型列表.所以编译器会让你输入任何你喜欢的东西(并警告它),并让你将它分配给一个不兼容的List<String>
变量(并警告它).
如果你说List<Number> l
,编译器会强制执行正确的类型(而不是让你分配它ls
).
无论您声明或不声明哪种泛型类型,这在运行时都没有影响.为了保持向后兼容性,泛型是一个完整的编译时功能.
或者是,在ls = l之后,堆中的空间也由List组成,也用于l参考?
如果你说
List l = new ArrayList<Integer>();
List<String> ls = l;
Object x = ls;
Collection<?> c = (Collection) x;
Run Code Online (Sandbox Code Playgroud)
你有四个不同的变量(有四种不同的类型声明),但它们都指向相同的数据(堆上的同一个对象).