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

mid*_*das 32 java generics list toarray

我只是看看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[]{});
Run Code Online (Sandbox Code Playgroud)

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

我已经写过玩具示例,它可以通用:

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);
}
}
Run Code Online (Sandbox Code Playgroud)

是否有任何理由宣布这种方式?

ben*_*y23 54

来自javadocs:

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

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

例如,对于您ArrayList<Integer>而不是Integer[]数组,您可能需要一个Number[]Object[]数组.

此外,该方法还检查传入的数组.如果传入的数组具有足够的空间用于所有元素,则该toArray方法重新使用该数组.这意味着:

Integer[] myArray = new Integer[myList.size()];
myList.toArray(myArray);
Run Code Online (Sandbox Code Playgroud)

要么

Integer[] myArray = myList.toArray(new Integer[myList.size()]);
Run Code Online (Sandbox Code Playgroud)

具有相同的效果

Integer[] myArray = myList.toArray(new Integer[0]);
Run Code Online (Sandbox Code Playgroud)

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

  • 它不是那么明显,Collection.toArray(新T [size])更快.请参阅此性能测试,证明Collection.toArray(新T [0])更快(至少在OpenJDK上)https://shipilev.net/blog/2016/arrays-wisdom-ancients/#_conclusion (3认同)
  • 有两种样式可以将集合转换为数组:使用预先确定大小的数组(如 c.toArray(new String[c.size()]))或使用空数组(如 c.toArray(new String[ 0]). 在较旧的 Java 版本中,建议使用预先调整大小的数组,因为创建适当大小数组所需的反射调用非常慢。OpenJDK 6 这个调用被内在化了,使得空数组版本的性能成为与预尺寸版本相比,相同,有时甚至更好。 (2认同)

rge*_*man 8

它通常被声明,以便您可以编写诸如此类的代码

Integer[] intArray = list.toArray(new Integer[0]);
Run Code Online (Sandbox Code Playgroud)

没有投射阵列回来.

它使用以下注释声明:

@SuppressWarnings("unchecked")
Run Code Online (Sandbox Code Playgroud)

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

  • 甚至不一定是虚拟参数.为了提高性能,可以使用`toArray(new Integer [list.size()])`并避免通过反射创建新数组. (2认同)