为什么ArrayList <e>构造函数允许原始ArrayList参数

时间:2016-11-17 09:20:56

标签: java generics type-erasure raw-types

为什么这段代码会编译:

ArrayList strings = new ArrayList();
strings.add("s1");
strings.add("s2");

ArrayList<Integer> numbers = new ArrayList<Integer>(strings);

鉴于有问题的构造函数需要Collection<? extends E>,其中E在这种情况下是整数?原始类型ArrayList中包含的对象如何成为E的子类?或者是否有一些隐藏的编译器魔法可以将其用于遗留目的?

2 个答案:

答案 0 :(得分:2)

检查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);

答案 1 :(得分:1)

编译器应该给你这个警告:

  

类型安全性:ArrayList类型的表达式需要取消选中   转换为符合Collection<? extends Integer>

说给定的参数(字符串)有问题。

尝试运行代码时也应该得到此异常:

  

java.lang.ClassCastException:java.lang.String无法强制转换为   java.lang.Integer中

没有编译错误的原因是没有正确定义ArrayList字符串,省略了String类型。所以编译可能只是猜测有什么东西。将您的代码更改为

ArrayList<String> strings = new ArrayList<String>();

你将得到编译错误

  

构造函数ArrayList<Integer>(ArrayList<String>)未定义