天天看點

Arrays.asList()你真的知道怎麼用嗎?

發現問題

前幾天在看别人的項目的時候,發現一個問題,簡單複現一下這個問題

// 注意這是一個Integer對象的數組哦
Integer[] arr = new Integer[]{9999,88,77};
List<Integer> list = Arrays.asList(arr);
// 執行以下操作,有問題麼?
list.add(1);
list.remove(0);
           

好的,如果你覺得沒錯,和我剛開始的想法一緻。在我沒有認真學習這個asList方法時,天真的以為沒有問題,顧名思義啊,就是把數組轉換成List呗。

// 恭喜,喜提報錯,如果是這樣測試該找你麻煩了,/(ㄒoㄒ)/~~ 
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(AbstractList.java:148)
	at java.util.AbstractList.add(AbstractList.java:108)
	at TestForAsList.main(TestForAsList.java:13)
           

廢話不多說,我們直接進源碼裡面看看。

@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);  // 看起來沒有任何異常,emm。然而呢,這個ArrayList并不是Java.util包下的ArrayList,而是一個在Arrays下實作的内部類。
}
           
Arrays.asList()你真的知道怎麼用嗎?

我們發現這個靜态内部類裡面并沒有實作List的add和remove方法。那麼子類将延用父類AbstractList的方法實作,這個繼承應沒有什麼問題。

// 我們進入這個父類的實作,發現了報錯的根源。。
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    
	public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }


    public E remove(int index) {
        throw new UnsupportedOperationException();
    }
}
           

總結:

究其原因,就是這個asList方法傳回的是一個内部類,隻實作了一些周遊以及更新的方法。下次使用它的時候需要注意一下。

擴充知識點

數組值的變化

然後我就發現了這個很有意思的點,就是這個Arrays包下的ArrayList用的是構造器傳進來的數組,并不像我們原來認為的ArrayList的那樣會拷貝數組然後建立一個新的數組。

這意味着我們在對這個List進行set的改動時,我們同時會更改原數組的值。

public static void main(String[] args) {
        Integer[] arr = new Integer[]{9999,88,77};
        List<Integer> list = Arrays.asList(arr);
        
        list.set(1,0);
        System.out.println(list.get(1));  // 輸出0
        System.out.println(arr[1]);  // 同樣也輸出了0
}
           

int[]數組

我們都知道int是基本資料類型,如果我們向asList()方法裡面傳入一個int[]數組會發生什麼呢?

我們知道泛型的話需要的是對象類型,基礎資料類型是不能作為泛型的。

// 此時int[]會作為一個對象類型,然後轉換為list。此時長度為1,且可以正常的取出來作為list元素
public static void main(String[] args) {
        int[] arr = new int[]{9999,88,77};
        List<int[]> list = Arrays.asList(arr);
        System.out.println(list.size());
        System.out.println(list.get(0)[0]);
        System.out.println(list.get(0)[1]);
        System.out.println(list.get(0)[2]);
}
           

好了,asList()方法就學廢了。一天學廢一個小知識/dog