Java List <T> T[] toArray(T[] a) 实现

2022-09-01 04:18:47

我只是在看List接口中定义的方法:,我有一个问题。为什么它是通用的?因此,方法不是完全的类型安全。以下代码片段编译,但会导致:<T> T[] toArray(T[] a)ArrayStoreException

List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);

String[] stringArray = list.toArray(new String[]{});

在我看来,如果toArray不是泛型的,并且采用List类型参数,那就更好了。

我已经写了玩具示例,它还可以witout generic:

package test;

import java.util.Arrays;

public class TestGenerics<E> {
    private Object[] elementData = new Object[10];
private int size = 0;

    public void add(E e) {
    elementData[size++] = e;
}

@SuppressWarnings("unchecked")
    //I took this code from ArrayList but it is not generic
public E[] toArray(E[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (E[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

    public static void main(String[] args) {

    TestGenerics<Integer> list = new TestGenerics<Integer>();
    list.add(1);
    list.add(2);
    list.add(3);
    //You don't have to do any casting
    Integer[] n = new Integer[10];
    n = list.toArray(n);
}
}

有什么理由以这种方式宣布它吗?


答案 1

来自 javadocs

与 toArray() 方法一样,此方法充当基于数组和基于集合的 API 之间的桥梁。此外,此方法允许精确控制输出数组的运行时类型,并且在某些情况下,可用于节省分配成本。

这意味着程序员可以控制它应该是什么类型的数组。

例如,对于您的数组,您可能需要一个 或 数组。ArrayList<Integer>Integer[]Number[]Object[]

此外,该方法还会检查传入的数组。如果传入的数组具有足够的空间来容纳所有元素,则该方法将重用该数组。这意味着:toArray

Integer[] myArray = new Integer[myList.size()];
myList.toArray(myArray);

Integer[] myArray = myList.toArray(new Integer[myList.size()]);

具有与相同的效果

Integer[] myArray = myList.toArray(new Integer[0]);

请注意,在较旧版本的Java中,后一种操作使用反射来检查数组类型,然后动态构造正确类型的数组。通过首先传入正确大小的数组,不必使用反射在方法内部分配新数组。现在情况已不再如此,两个版本可以互换使用。toArray


答案 2

它是通用声明的,以便您可以编写代码,例如

Integer[] intArray = list.toArray(new Integer[0]);

不强制转换数组返回。

它使用以下注释进行声明:

@SuppressWarnings("unchecked")

换句话说,Java 信任传入相同类型的数组参数,因此不会发生错误。