2016-11-17 69 views
2

为什么这个代码编译:为什么ArrayList的<E>构造允许原始的ArrayList参数

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

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

鉴于所涉及的构造函数需要一个Collection<? extends E>其中E在这种情况下是整型?如何将原始类型ArrayList中的对象包含在E的子类中?或者是否有一些隐藏的编译器魔术可以实现这一目的?

+1

我想这是因为兼容性。由于编译器无法知道哪些对象在“字符串”中,因此它假定其中存在正确的对象。 如果编译器的行为不同(并且不允许这样做),那么从(旧)非泛型使用代码到泛型的改变几乎是不可能的。 –

+0

这只是众所周知的原始类型转换的一个实例:'列表 numbers = new ArrayList();'。 –

回答

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); 
+0

这并不能解释原始'ArrayList'中的元素如何满足'?扩展E'。 –

1

编译器应该给你这样的警告:

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

说,也有一些是错误的给定参数(字符串)。

你也应该在尝试运行代码时,此异常:

java.lang.ClassCastException:java.lang.String中不能转换为java.lang.Integer的

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

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

,你会得到编译错误

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

相关问题