ArrayList的 toArray() 与 toArray(T[] a)

一、public Object[] toArray()与public T[] toArray(T[] a)

先来看看一段代码:

public static void main(String[] args) throws Exception {
    List<String> list = new ArrayList<>();
    list.add("dddd");
    list.add("eeee");
    list.add("qqqq");

    String[] strings = (String[])list.toArray();
}

运行后顺理成章地报错:

Exception in thread “main” java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

类型装换错误,什么原因呢?
看下下面代码的输出

public static void main(String[] args) throws Exception {
    Object[] objects = new Object[]{};
    String[] strings = new String[]{};
    System.out.println(objects.getClass());
    System.out.println(strings.getClass());
}

输出:

class [Ljava.lang.Object;

class [Ljava.lang.String;

所以直接调用Arraylist的toArray()方法就报错了。
看看ArrayList的源码:

public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

点击去看 Arrays.copyOf()在Arrays中的实现:

public static <T> T[] copyOf(T[] original, int newLength) {
   return (T[]) copyOf(original, newLength, original.getClass());
}   

从original.getClass()这句可以知道获取的类型是ArrayList中elementData的类型,而elementData在Arraylist是如何定义的呢:

 transient Object[] elementData;

从刚才打印出的类型信息可以知道, elementData的类型是:[Ljava.lang.Object;
所以将elementData转为类型信息为[Ljava.lang.String;的String[]就报错了。

那么Arraylist是怎么解决的呢?
答案是:

public <T> T[] toArray(T[] a)

看看源码的实现:

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;
}

源码中的a.getClass()指明了在调用toArray(T[] a)方法时将需要的类型信息传进来就行了。
如何使用?

   String[] strings = (String[])list.toArray(new String[0]);

二、
在看到public T[] toArray(T[] a)的源码实现时,看到这段时有个点不明白:

    if (a.length > size) 
        a[size] = null; 

为什么被复制进的数组长度大于list中实际元素时要将数组下标为size位置的元素置为null?而后面的元素呢?看了方法注释,说明了问题:

If the list fits in the specified array with room to spare(i.e., the array has more elements than the list), the element in the array immediately following the end of the collection is set to null. (This is useful in determining the length of the list only if the caller knows that the list does not contain any null elements.)

如果list在数组中有多余的空间(例如,数组的元素多与list的元素),在数组中填充完集合的元素后将数组接下来的元素置为null。(这仅用在调用者知道list中不包括null元素时用来判断list的长度。)

这说明了置为null的这一个元素起的是标记的作用,调用者可以通过null来判断复制进数组中的list的长度。
看看如下代码:

public static void main(String[] args) throws Exception {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);

    Object[] objects = new Object[]{8, 8, 8, 8, 8};
    list.toArray(objects);
    System.out.println(Arrays.asList(objects));
} 

输出:

[1, 2, 3, null, 8],所以原list的长度为3。

你可能感兴趣的:(集合)