正確認識Arrays.asList方法

Arrays工具類提供了一個方法asList, 使用該方法能夠將一個變長參數或者數組轉換成List html

其源代碼以下:java

/**
     * Returns a fixed-size list backed by the specified array.  (Changes to
     * the returned list "write through" to the array.)  This method acts
     * as bridge between array-based and collection-based APIs, in
     * combination with {@link Collection#toArray}.  The returned list is
     * serializable and implements {@link RandomAccess}.
     *
     * <p>This method also provides a convenient way to create a fixed-size
     * list initialized to contain several elements:
     * <pre>
     *     List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
     * </pre>
     *
     * @param a the array by which the list will be backed
     * @return a list view of the specified array
     */
    @SafeVarargs
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

 

問題發現

根據上述方法的描述,咱們先來編寫幾個例子:api

/**
 * @author wangmengjun
 *
 */
public class ArrayExample {
    
    public static void main(String[] args) {
        
        /**使用變長參數*/
        List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
        System.out.println(array1);
        
        /**使用數組*/
        List<String> array2 =  Arrays.asList(new String[] {"Welcome", "to","Java", "world"});
        System.out.println(array2);
    }

}

 

運行上述程序,輸出以下內容。數組

[Welcome, to, Java, world]
[Welcome, to, Java, world]

 

心血來潮,忽然想在建立的列表中添加一個字符串「Cool~~~」,  走一個。oracle

/**使用變長參數*/
        List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
        array1.add("Cool~~~");

結果,遇到一個UnsupportedOperationException異常:dom

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(Unknown Source)
	at java.util.AbstractList.add(Unknown Source)
	at test.ArrayExample.main(ArrayExample.java:36)

難以想象,new ArrayList<>(a)產生的列表調用add方法,居然遇到問題。ide

緣由查找

那麼問題來了,到底發生了什麼事情?帶着疑問,去查看一下Arrays.asList中使用的ArrayList到底長啥樣?工具

原來Arrays的asList方法使用的ArrayList類是一個內部定義的類而不是java.util.ArrayList類this

其源代碼以下:url

/**
     * @serial include
     */
    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的實現能夠看出,它繼承了抽象類java.util.AbstractList<E>, 可是沒有重寫addremove方法,沒有給出具體的實現

可是,默認狀況下,java.util.AbstractList類在addset以及remove方法中,直接會拋出UnsupportedOperationException異常。AbstractList的部分源代碼以下:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    /**
     * Sole constructor.  (For invocation by subclass constructors, typically
     * implicit.)
     */
    protected AbstractList() {
    }

    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     *
     * <p>This implementation always throws an
     * {@code UnsupportedOperationException}.
     *
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @throws IllegalArgumentException      {@inheritDoc}
     * @throws IndexOutOfBoundsException     {@inheritDoc}
     */
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     *
     * <p>This implementation always throws an
     * {@code UnsupportedOperationException}.
     *
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws IndexOutOfBoundsException     {@inheritDoc}
     */
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }
}

 

正是由於java.util.Arrays類的內部類ArrayList沒有重寫add和remove方法,因此,當咱們調用其add方法時,其實就是調用了AbstractList類的add方法,結果就是直接拋出UnsupportedOperationException異常。

同理,在調用remove方法,或者調用與add、remove方法相關聯的其它方法(如addAll)一樣會遇到UnsupportedOperationException異常。

addAll的例子

/**
 * @author wangmengjun
 *
 */
public class ArrayExample {

    public static void main(String[] args) {

        /**使用變長參數*/
        List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
        array1.addAll(Arrays.asList("AAA", "BBB"));
    }

}

 

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(Unknown Source)
	at java.util.AbstractList.add(Unknown Source)
	at java.util.AbstractCollection.addAll(Unknown Source)
	at test.ArrayExample.main(ArrayExample.java:36)

 

set的例子:

/**
 * @author wangmengjun
 *
 */
public class ArrayExample {

    public static void main(String[] args) {

        /**使用變長參數*/
        List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
        System.out.println(array1);
        
        //將Java替換成hello
        array1.set(2, "hello");
        System.out.println(array1);
    }

}

正是因爲Arrays的內部類ArrayList重寫了set方法,因此上述程序可以正常運行,不會再拋出UnsupportedOperationException異常。

結果以下:

[Welcome, to, Java, world]
[Welcome, to, hello, world]

 

使用場景

從上述的例子和簡單分析來看,Arrays工具類提供了一個方法asList, 使用該方法能夠將一個變長參數或者數組轉換成List 

可是,生成的List的長度是固定的;可以進行修改操做(好比,修改某個位置的元素)不能執行影響長度的操做(如add、remove等操做)。會拋出UnsupportedOperationException異常

Arrays.asList比較適合那些已經有數組數據或者一些元素,而須要快速構建一個List,只用於讀取操做,而不進行添加或刪除操做的場景。

若是,想要根據已知數組數據,快速獲取一個可進行增刪改查的列表List,一個比較簡單的方法以下:

從新使用java.util.ArrayList包裝一層。

/**
 * @author wangmengjun
 *
 */
public class ArrayExample {

    public static void main(String[] args) {

        /**使用變長參數*/
        List<String> array1 = new ArrayList<>(Arrays.asList("Welcome", "to", "Java", "world"));
        System.out.println(array1);

        array1.add("Cool~~~");
        System.out.println(array1);

    }

}

結果以下:

[Welcome, to, Java, world]
[Welcome, to, Java, world, Cool~~~]
相關文章
相關標籤/搜索