項目中經常使用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接口,所以這里得到的
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
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值,並不是真正數組元素。
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());
