Arrays.asList使用注意事項


項目中經常使用Arrays.asList方法方便的得到的list,發現有很多細節的知識點可以總結一下,總結的注意事項有以下幾點:

1)通過Arrays.asList方法得到的list是固定大小的,不可以add或remove方法去改變list的元素

2)不支持基礎數據類型的轉換

3)改變原始數組的內容或者改變通過Arrays.asList方法得到的list的元素值值,相互之間的數據都會自動更新,因為這個方法是將數組和列表鏈接起來

 

下面來通過測試解釋一下原因:

1)通過Arrays.asList方法得到的list是固定大小的,不可以add或remove方法去改變list的元素

 看源碼我們可以看到Arrays.asList是通過Arrays的一個內部類ArrayList實現的,這個內部類繼承自AbstractList同時實現了RandomAccess和Serializable接口,所以這里得到的

ArrayList 並不是 java.util.ArrayList ,而是 java.util.Arrays 的一個內部類,這個內部類用一個 final 數組來保存元素。
private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable

繼承的AbstractList中對add、remove、set方法是直接拋異常的,也就是說如果繼承的子類沒有去重寫這些方法,那么子類的實例去調用這些方法是會直接拋異常的

下面是AbstractList中方法的定義,我們可以看到具體拋出的異常:

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

我們來驗證一下結論是不是這樣的,轉換之后我們調用一下add方法:

public class ArraysListTest {

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

    }
}

看下運行的結果:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)

拋出來異常和AbstractList中add方法定義拋出來的異常是一樣,也驗證了是不可操作的

那我們再驗證一下set方法,再獲取到list后,通過set方法去改變第一個元素的值,測試用例如下:

public class ArraysListTest {

    public static void main(String[] args) {
        Integer[] a_Integer= new Integer[] { 1, 2, 3, 4 };
        List a_Integer_List = Arrays.asList(a_Integer);
        a_Integer_List.set(0,888);
        foreach(a_Integer_List);
    }
    /*打印方法*/
    private static void foreach(List list) {
        for (Object object : list) {
            System.out.println(object + " ");
        }

        System.out.println();

    }
}

看戲運行結果:

888 
2 
3 
4 

不僅沒有拋異常,還能做到改變第一個元素的值,這是為什么呢?結論是Arrays內部定義的內部類ArrayList重寫了set方法,使得set功能是可以操作的

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

 

2)不支持基礎數據類型的轉換

 Java中的基礎數據類型(byte,short,int,long,float,double,boolean)是不支持使用Arrays.asList方法去轉換的

首先看下Arrays.asList方法的定義:

    public static <T> List<T> asList(T... a) {}

參數類型是一個T,根據官方文檔的描述,T 是數組元素的 class

我們知道任何類型的對象都有一個 class 屬性,這個屬性代表了這個類型本身。我們常用的反射技術,也是通過class來獲取到一個對象,原生數據類型,比如 int,short,long等,是沒有這個屬性的,具有 class 屬性的是它們所對應的包裝類 Integer,Short,Long,可以理解為asList 方法的參數必須是對象或者對象數組,而基礎數據類型不是對象——這也正是包裝類出現的一個主要原因。當傳入一個基礎數據類型數組時,asList 的真正得到的參數就不是數組中的元素,而是 數組對象本身,此時List 的唯一元素就是這個數組。
 
我們定義一個基礎類型的數組,使用asList轉換后得到的結果:
public class ArraysListTest {

    public static void main(String[] args) {
        int [] a_int = { 1, 2, 3, 4 };
        /*預期輸出應該是在1,2,3,4,但實際上輸出的僅僅是一個引用,這里它把a_int 當成一個元素*/
        List a_int_List = Arrays.asList(a_int);
        foreach(a_int_List);
        /*為此我們需要這樣遍歷其中元素*/
        foreachForBase(a_int_List);
    }
    /*打印方法*/
    private static void foreach(List list) {
        for (Object object : list) {
            System.out.println(object + " ");
        }
        System.out.println();
    }
    private static void foreachForBase(List a_int_List) {
        int[] _a_int = (int[]) a_int_List.get(0);
        foreach(_a_int);
    }
    private static void foreach(int[] a_int) {
        for (int i : a_int) {
            System.out.println(i + " ");
        }
        System.out.println();
    }
}

 

看下運行的結果:
[I@36f6e879 

1 
2 
3 
4 

我們可以看到第一個打印出來的結果是數組對象的hashcode值,並不是真正數組元素。

那么如果我們想對基礎數據類型的數組使用asList,就需要先轉換為包裝類型或者在申明的時候就定義為包裝類型。
 

3)改變原始數組的內容或者改變通過Arrays.asList方法得到的list的元素值值,相互之間的數據都會自動更新,因為這個方法是將數組和列表鏈接起來 

當我們去改變其中的list或者數組的元素時,兩個是同時改變的,轉后list后,我們改變list中元素的值,再看下數組的值:
public class ArraysListTest {

    public static void main(String[] args) {
        Integer[] a_Integer= new Integer[] { 1, 2, 3, 4 };
        List a_Integer_List = Arrays.asList(a_Integer);
        a_Integer_List.set(0,888);
        foreach(a_Integer_List);
        foreach(a_Integer);
    }
    /*打印方法*/
    private static void foreach(List list) {
        for (Object object : list) {
            System.out.println(object + " ");
        }
        System.out.println();
    }
    private static void foreach(Integer[] _a_Integer) {
        for (int i : _a_Integer) {
            System.out.println(i + " ");
        }
        System.out.println();
    }
}

看下運行的效果:

888 
2 
3 
4 

888 
2 
3 
4 

可以看到數組的值也跟着改變了,發過來改變數組的值,list元素的值也是變更的,因為asList獲得List實際引用的就是數組

 

最后,如果我們想得到一個真正的可操作的list通過什么方法呢?

第一種最簡便的方式:new 一個真正的java.util.ArrayList 

        List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3));

第二種使用Java8的stream方式:

Integer [] myArray = { 1, 2, 3 };
List myList = Arrays.stream(myArray).collect(Collectors.toList());
//基本類型也可以實現轉換(依賴boxed的裝箱操作)
int [] myArray2 = { 1, 2, 3 };
List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM