一般情況下,使用Arrays.asList()的原因無非是想將數組或一些元素轉爲集合,而你得到的集合並不一定是你想要的那個集合。
asList在最初設計時用於打印數組,但jdk1.5開始,有了另一個比較更方便的打印函數Arrays.toString(),於是打印不再使用asList(),而asList()恰巧可用於將數組轉爲集合。
一、首先看幾個例子:
(1)將基本類型數組作爲asList參數
String[] strArr = {"A","B","C"};
List<String> asList = Arrays.asList(strArr);
System.out.println("封裝類型String時:" + asList.size());
int[] intArr = {1, 2, 3};
List<String> list = Arrays.asList(intArr);
System.out.println("基本類型時:" + list.size());
運行結果:
封裝類型String時:3
基本類型時:1
(2)將數組作爲asList參數後,修改數組或List
String[] strArr = {"A","B","C"};
List<String> asList = Arrays.asList(strArr);
strArr[0] = "a";
asList.set(1, "b");
System.out.println(Arrays.toString(strArr));
System.out.println(asList.toString());
運行結果:
[a, b, C]
[a, b, C]
strArr和asList 中的數據都會改變
(3)數組轉換爲集合後,進行增刪元素
String[] strArr = {"A","B","C"};
List<String> asList = Arrays.asList(strArr);
asList.add("1");
asList.remove("C");
System.out.println(asList.toString());
運行結果:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at com.my.tests.TestArrayAsList.main(TestArrayAsList.java:9)
二、深入研究
這裏要關注的地方在於:
Arrays.asList()返回的List是:Arrays.ArrayList,而不是java.util.ArrayList
兩者的不同之處:
Arrays.ArrayList是工具類Arrays的一個內部靜態類,它沒有完全實現List方法,而ArrayList直接實現了List接口,實現了List所有方法。
- 長度不同和實現的方法不同:
Arrays.ArrayList是一個定長集合,因爲它沒有重寫add,remove方法,所以,一旦初始化元素後,集合的size就是不可變的。 - 參數賦值方式不同
Arrays.ArrayList將外部數組的引用直接通過“=”賦予內部的泛型數組,所以本質指向同一個數組。而ArrayList是將其他集合轉爲數組後copy到自己內部的數組的。
// 以下是JDK8版本中的Arrays.ArrayList
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array); // 此處是直接賦值的,所以本質指向的是同一個數組
}
}
// 以下是JDK8中java.util.ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); // toArray底層使用的是數組clone或System.arraycopy
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
三、案例解析
對於第一個例子:(1)將基本類型數組作爲asList參數
由於Arrays.ArrayList參數爲可變長泛型,而基本類型是無法泛型化的,所以它把int[] arr數組當成了一個泛型對象,所以集合中最終只有一個元素arr。
對於第二個例子:(2)將數組作爲asList參數後,修改數組或List
由於asList產生的集合元素是直接引用作爲參數的數組,所以當外部數組或集合改變時,數組和集合會同步變化,這在平時我們編碼時可能產生莫名的問題。
對於第三個例子:(3)數組轉換爲集合後,進行增刪元素
由於asList產生的集合並沒有重寫add,remove等方法,所以它會調用父類AbstractList的方法,而父類的方法中拋出的卻是異常信息。
四、支持基礎類型的方式
1、如果使用Spring
import org.springframework.util.CollectionUtils;
public class Temp {
public static void main(String[] args) {
int[] arr = {1,2,3};
List list = CollectionUtils.arrayToList(arr);
System.out.println(list);
}
}
運行結果:
[1, 2, 3]
2、直接使用Java8
int intArray[] = {1,2,3};
List<Integer> iList = Arrays.stream(intArray)
.boxed()
.collect(Collectors.toList());
System.out.println(iList);
運行結果:
[1, 2, 3]
五、數組轉ArrayList
1、遍歷轉換
Integer intArray[] = {1,2,3};
ArrayList<Integer> arrayList = new ArrayList<>();
for (Integer i : arrayList) {
arrayList.add(i);
}
2、使用工具類(更加優雅)
ArrayList<String> list = new ArrayList();
Collections.addAll(list, "A", "B", "C");
3、對於JAVA8
既可以用於基本類型也可以返回想要的集合。
int intArray[] = {1,2,3};
List<Integer> iList = Arrays.stream(intArray)
.boxed()
.collect(Collectors.toList());
System.out.println(iList);
運行結果:
[1, 2, 3]
4、還有另外一種方法
兩個集合類結合:將Arrays.asList返回的集合作爲ArrayList的構造參數
ArrayList arrayList = new ArrayList<>(
Arrays.asList("A", "B", "C")
);