【问题标题】:Why does ArrayList<E> constructor allow a raw ArrayList parameter为什么 ArrayList<E> 构造函数允许原始 ArrayList 参数
【发布时间】:2016-11-17 09:20:55
【问题描述】:

为什么这段代码会编译:

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

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

鉴于有问题的构造函数需要一个Collection&lt;? extends E&gt;,在这种情况下E 是整数?原始类型ArrayList 中的对象如何包含在E 的子类中?或者是否有一些隐藏的编译器魔法允许它用于遗留目的?

【问题讨论】:

  • 我认为这是因为兼容性。由于编译器无法知道哪些对象在“字符串”中,它假定其中有正确的对象。如果编译器的行为不同(并且不允许这样做),那么从使用代码的(旧)非泛型到泛型的更改几乎是不可能的。
  • 这只是众所周知的原始类型转换的一个实例:List&lt;Integer&gt; numbers = new ArrayList();

标签: java generics type-erasure raw-types


【解决方案1】:

检查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&lt;? extends E&gt; c) 将接受所有Collection,不要在意E 类型

当我们使用它时它会抛出ClassCastExceptionwhen

Integer i= numbers.get(1);

【讨论】:

  • 这并没有解释原始ArrayList 中的元素如何满足? extends E
【解决方案2】:

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

类型安全:ArrayList 类型的表达式需要不检查 转换为符合Collection&lt;? extends Integer&gt;

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

您在尝试运行代码时也应该得到这个异常:

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

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

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

你会得到编译错误

构造函数ArrayList&lt;Integer&gt;(ArrayList&lt;String&gt;)未定义

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-17
    • 2015-06-06
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    相关资源
    最近更新 更多