ArrayList.toArray()中的Java泛型

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (36)

假设你有一个数组列表,定义如下:

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

后来在你的代码中,由于泛型,你可以这样说:

String someLine = someData.get(0);

编译器知道它会得到一个字符串。耶泛型!但是,这会失败:

String[] arrayOfData = someData.toArray();

toArray()将始终返回一个对象数组,而不是定义的泛型。为什么该get(x)方法知道它正在返回什么,但toArray()默认为Objects?

提问于
用户回答回答于

如果你看一下执行toArray(T[] a)的ArrayList <E>类,它是这样的:

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

这个方法的问题是你需要传递相同泛型类型的数组。现在考虑这个方法是否没有任何争论,那么实现将会类似于:

public <T> T[] toArray() {
    T[] t = new T[size]; // compilation error
    return Arrays.copyOf(elementData, size, t.getClass());
}

但是这里的问题是你不能用Java创建通用数组,因为编译器不知道T代表什么。换句话说,Java中不允许创建不可修饰类型的数组(JLS§4.7)。

Array Store Exception(JLS§10.5)的另一个重要引用:

如果数组的组件类型不可确定(§4.7),那么Java虚拟机将无法执行上一段中描述的存储检查。这就是为什么禁止使用不可指定元素类型的数组创建表达式(第15.10.1节)。

这就是为什么Java提供了重载版本toArray(T[] a)

我将重写toArray()方法来告诉它它将返回一个E数组。

因此,而不是重写toArray(),你应该使用toArray(T[] a)

无法从Java文档创建类型参数的实例对您而言可能也很有趣。

用户回答回答于

通用信息在运行时被删除。JVM不知道你的列表是否是List<String>List<Integer>(在运行TList<T>被解析为Object),所以唯一可能的数组类型Object[]

你可以使用toArray(T[] array)- 在这种情况下,JVM可以使用给定数组的类,你可以在ArrayList实现中看到它:

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());

扫码关注云+社区