Arrays.asList与 Collection.toArray

## Arrays.asList##
通过源码来解释2个问题
1 Arrays.asList返回指定数组的列表视图。
2 Arrays.asList返回的ArrayList不能进行add,remove操作(异常)。

Arrays.asList源码:

public static <T> List<T> asList(T... a) {
    return new ArrayList<T>(a);
}

可以看到返回了一个ArrayList,这个ArrayList是Arrays定义的内部类,而不是通常的java.util.ArrayList。

Arrays$ArrayList 源码:

private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {
        private static final long serialVersionUID = -2764017481108945198L;
    private final E[] a;

    ArrayList(E[] array) {
            if (array==null)
                throw new NullPointerException();
        a = array;
    }

    public int size() {
        return a.length;
    }

    public Object[] toArray() {
        return a.clone();
    }

    public <T> T[] toArray(T[] a) {
        int size = size();
        if (a.length < size)
        return Arrays.copyOf(this.a, size,
                     (Class<? extends T[]>) a.getClass());
        System.arraycopy(this.a, 0, a, 0, size);
        if (a.length > size)
        a[size] = null;
        return a;
    }

    public E get(int index) {
        return a[index];
    }

    public E set(int index, E element) {
        E oldValue = a[index];
        a[index] = element;
        return oldValue;
    }

        public int indexOf(Object o) {
            if (o==null) {
                for (int i=0; i<a.length; i++)
                    if (a[i]==null)
                        return i;
            } else {
                for (int i=0; i<a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }
    }

外部数组的引用通过构造函数传递到ArrayList内部。
ArrayList的api都是基于该引用的操作。
所以ArrayList的操作会直接作用于作为构造器参数的外部数组上。
这就解释了“Arrays.asList返回指定数组的列表视图”。

可以看到Arrays$ArrayList的定义中并没有定义add(),remove()方法,追根溯源到它的父类AbstractList

AbstractList源码:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    public boolean add(E e) {
        add(size(), e);
        return true;
    }   
    public void add(int index, E element) {
    throw new UnsupportedOperationException();
    }
    public E remove(int index) {
    throw new UnsupportedOperationException();
    }
    ...
    ...
    ...
}

可以看出AbstractList中关于add()remove()的方法都是具体而不是abrstract方法,所以Arrays$ArrayList沿用了父类的add()remove()方法,AbstractListadd()remove()方法的定义解释了 “Arrays.asList返回的ArrayList不能进行add,remove操作(异常)”

## Collection.toArray##

这里就以java.util.ArrayList的实现为例,看一下它的toArray方法如何实现。

ArrayList.toArray源码:

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

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


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

这是ArrayList的两个toArray方法,其中都调用了 Arrays.copyOf()方法,并且最后都调用了定义如下的copyOf方法

Arrays.copyOf源码:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

可以得出以下结论:
1 toArray()方法返回的是一个new出来的数组,跟Arrays.asList返回视图不同
2 toArray(T[] a),a.length小于集合的size时,返回的数组跟a没有任何关系,是new出来的,a.length大于集合的size时,会将集合内容copy到a中,然后将a返回
3 toArray()api返回的是Object[],观察源码可以知道它返回的其实是类型与集合元素类型相同的数组,只是为了api的通用性(不可能每种类型都提供一个toArray()),所以将接口的返回值定位Object[],所以可以放心的将返回的Object[]强转为集合元素类型的数组。
4 toArray(T[] a)则总会返回T[],有可能是新建的,也有可能是作为参数的T[],取决于a.length与集合的size的大小关系,前面又说。

你可能感兴趣的:(toArray,asList)