为什么这段代码可以编译:
ArrayList strings = new ArrayList();
strings.add("s1");
strings.add("s2");
ArrayList<Integer> numbers = new ArrayList<Integer>(strings);
假设构造函数期望Collection<? extends E>
,其中E
在这种情况下是整数?原始类型ArrayList
中包含的对象如何成为E
的子类?或者有一些隐藏的编译器魔力允许这用于遗留目的?
检查ArrayList
构造函数:
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
elementData
是对象数组
transient Object[] elementData;
所以新的ArrayList(Collection<? extends E> c)
将接受所有的Collection
,不关心E
类型
当我们使用它时,它会抛出ClassCastExceptionwhen
:
Integer i= numbers.get(1);
编译器会给你这样的警告:
类型安全:不检查ArrayList类型的表达式转换为符合
Collection<? extends Integer>
表示给定的参数(字符串)有问题。
你也应该得到这个异常时,试图运行代码:
. lang。ClassCastException: java.lang.String不能强制转换为java.lang.Integer
你没有得到编译错误的原因是数组列表字符串没有正确定义,你省略了String类型。所以编译器可能只是猜测出了什么问题。将代码更改为
ArrayList<String> strings = new ArrayList<String>();
,你会得到编译错误
构造函数
ArrayList<Integer>(ArrayList<String>)
是undefined