java集合細節:asList的缺陷

在實際開發過程當中咱們常常使用asList講數組轉換爲List,這個方法使用起來很是方便,可是asList方法存在幾個缺陷:java

1、避免使用基本數據類型數組轉換爲列表

        使用8個基本類型數組轉換爲列表時會存在一個比較有味的缺陷。先看以下程序:apache

public static void main(String[] args) {  
        int[] ints = {1,2,3,4,5};  
        List list = Arrays.asList(ints);  
        System.out.println("list'size:" + list.size());  
    }  
    ------------------------------------  
    outPut:  
    list'size:1  

 

        程序的運行結果並無像咱們預期的那樣是5而是逆天的1,這是什麼狀況?先看源碼:數組

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

 

        asList接受的參數是一個泛型的變長參數,咱們知道基本數據類型是沒法泛型化的,也就是說8個基本類型是沒法做爲asList的參數的, 要想做爲泛型參數就必須使用其所對應的包裝類型。可是這個這個實例中爲何沒有出錯呢?由於該實例是將int 類型的數組當作其參數,而在Java中數組是一個對象,它是能夠泛型化的。因此該例子是不會產生錯誤的。dom

        實際上:a.size()  debug過來是 [[1, 2, 3, 4, 5]]工具

 

既然例子是將整個int 類型的數組當作泛型參數,那麼通過asList轉換就只有一個int 的列表了。以下:spa

public static void main(String[] args) {  
    int[] ints = {1,2,3,4,5};  
    List list = Arrays.asList(ints);  
    System.out.println("list 的類型:" + list.get(0).getClass());  
    System.out.println("list.get(0) == ints:" + list.get(0).equals(ints));  
}  
--------------------------------------------  
outPut:  
list 的類型:class [I  
list.get(0) == ints:true  

 

        從這個運行結果咱們能夠充分證實list裏面的元素就是int數組。弄清楚這點了,那麼修改方法也就一目瞭然了:將int 改變爲Integer。debug

public static void main(String[] args) {  
        Integer[] ints = {1,2,3,4,5};  
        List list = Arrays.asList(ints);  
        System.out.println("list'size:" + list.size());  
        System.out.println("list.get(0) 的類型:" + list.get(0).getClass());  
        System.out.println("list.get(0) == ints[0]:" + list.get(0).equals(ints[0]));  
    }  
    ----------------------------------------  
    outPut:  
    list'size:5  
    list.get(0) 的類型:class java.lang.Integer  
    list.get(0) == ints[0]:true  

 

>>>>>>Java細節(2.1):在使用asList時不要將基本數據類型當作參數。code

2、asList產生的列表不可操做

        對於上面的實例咱們再作一個小小的修改:對象

public static void main(String[] args) {  
        Integer[] ints = {1,2,3,4,5};  
        List list = Arrays.asList(ints);  
        list.add(6);  
    }  

 

        該實例就是講ints經過asList轉換爲list 類別,而後再經過add方法加一個元素,這個實例簡單的不能再簡單了,可是運行結果呢?打出咱們所料:繼承

Exception in thread "main" java.lang.UnsupportedOperationException  
    at java.util.AbstractList.add(Unknown Source)  
    at java.util.AbstractList.add(Unknown Source)  
    at com.chenssy.test.arrayList.AsListTest.main(AsListTest.java:10)  

 

        運行結果盡然拋出UnsupportedOperationException異常,該異常表示list不支持add方法。這就讓咱們鬱悶了,list怎麼可能不支持add方法呢?難道jdk腦殼堵塞了?咱們再看asList的源碼:

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

 

        asList接受參數後,直接new 一個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;  
        }  
        //.................  
    }  

 

        這是ArrayList的源碼,從這裏咱們能夠看出,此ArrayList不是java.util.ArrayList,他是Arrays的內部類。該內部類提供了size、toArray、get、set、indexOf、contains方法,而像add、remove等改變list結果的方法從AbstractList父類繼承過來,同時這些方法也比較奇葩,它直接拋出UnsupportedOperationException異常:

public boolean add(E e) {  
        add(size(), e);  
        return true;  
    }  
      
    public E set(int index, E element) {  
        throw new UnsupportedOperationException();  
    }  
      
    public void add(int index, E element) {  
        throw new UnsupportedOperationException();  
    }  
      
    public E remove(int index) {  
        throw new UnsupportedOperationException();  
    }  

 

        經過這些代碼能夠看出asList返回的列表只不過是一個披着list的外衣,它並無list的基本特性(變長)。該list是一個長度不可變的列表,傳入參數的數組有多長,其返回的列表就只能是多長。因此:

>>>>>>Java細節(2.2):不要試圖改變asList返回的列表,不然你會自食苦果。

 

    解決方案

        若是想根據數組獲得一個新的正常的list,固然可能夠循環一個一個添加,也能夠纔有如下2個種方法:

ArrayList<Integer> copyArrays=new ArrayList<Integer>(Arrays.asList(i));
//這樣就是獲得一個新的list,可對其進行add,remove了  
copyArrays.add(222);//正常,不會報錯  
  
Collections.addAll(new ArrayList<Integer>(5), i);
//或者新建一個空的list,把要轉換的數組用Collections.addAll添加進去  


若是你想直接根據基本類型的數組如int[],long[]直接用asList轉成list,那麼咱們能夠選擇用apache commons-lang工具包裏的數組工具類ArrayUtils類的toObject()方法,很是方便,以下:

Arrays.asList(ArrayUtils.toObject(i));
//上邊的代碼:int i[]={11,22,33};達到了咱們想要的效果  


這個類功能很強大:

還能「逆向」轉過來,具體就不說了。

相關文章
相關標籤/搜索