千萬別這樣使用Arrays.asList詳解
前言
使用Arrays.asList()的原因無非是想將數(shù)組或一些元素轉(zhuǎn)為集合,而你得到的集合并不一定是你想要的那個(gè)集合。
而一開始asList的設(shè)計(jì)時(shí)用于打印數(shù)組而設(shè)計(jì)的,但jdk1.5開始,有了另一個(gè)比較更方便的打印函數(shù)Arrays.toString(),于是打印不再使用asList(),而asList()恰巧可用于將數(shù)組轉(zhuǎn)為集合。
1、錯(cuò)誤用法
如果你這樣使用過,那你可要注意了。
錯(cuò)誤一
將基本類型數(shù)組作為asList的參數(shù)
int[] arr = {1,2,3};
List list = Arrays.asList(arr);
System.out.println(list.size());
猜一下輸出結(jié)果?
錯(cuò)誤二
將數(shù)組作為asList參數(shù)后,修改數(shù)組或List
String[] arr = {"歡迎","關(guān)注","Java"};
List list = Arrays.asList(arr);
arr[1] = "愛上";
list.set(2,"我");
System.out.println(Arrays.toString(arr));
System.out.println(list.toString());
猜一下輸出結(jié)果?
錯(cuò)誤三
數(shù)組轉(zhuǎn)換為集合后,進(jìn)行增刪元素
String[] arr = {"歡迎","關(guān)注","Java"};
List list = Arrays.asList(arr);
list.add("新增");
list.remove("關(guān)注");
System.out.println(list.toString());
猜一下輸出結(jié)果?
你是不是以為上面 👆那個(gè) list 是 java.util.ArrayList ?
答案很確定:NO !
2、深入探究
我們通過asList()源碼可發(fā)現(xiàn)其原因,但為了更直觀,我們先通過IDEA debug來看看結(jié)果。
List<String> asList = Arrays.asList("歡迎","關(guān)注","碼上實(shí)戰(zhàn)");
ArrayList<String> aList = new ArrayList<>(asList);

其實(shí)它返回的是 java.util.Arrays.ArrayList,這個(gè)家伙是誰呢?
請(qǐng)看下源碼:
public class Arrays {
//省略其他方法
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
//就是這個(gè)家伙 👇
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable{
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
//省略其他方法
}
}
但它和ArrayList貌似很像唉!有什么不同嗎?
3、不同之處
Arrays.ArrayList 是工具類 Arrays 的一個(gè)內(nèi)部靜態(tài)類,它沒有完全實(shí)現(xiàn)List的方法,而 ArrayList直接實(shí)現(xiàn)了List 接口,實(shí)現(xiàn)了List所有方法。

長(zhǎng)度不同 和 實(shí)現(xiàn)的方法不同
Arrays.ArrayList是一個(gè)定長(zhǎng)集合,因?yàn)樗鼪]有重寫add,remove方法,所以一旦初始化元素后,集合的size就是不可變的。
參數(shù)賦值方式不同
Arrays.ArrayList將外部數(shù)組的引用直接通過“=”賦予內(nèi)部的泛型數(shù)組,所以本質(zhì)指向同一個(gè)數(shù)組。
ArrayList(E[] array) {
a = array;
}
ArrayList是將其他集合轉(zhuǎn)為數(shù)組后copy到自己內(nèi)部的數(shù)組的。
public ArrayList(Collection<? extends E> c) {
// toArray 底層使用的是 數(shù)組clone 或 System.arraycopy
elementData = c.toArray();
}
4、揭曉答案
錯(cuò)誤一
由于Arrays.ArrayList參數(shù)為可變長(zhǎng)泛型,而基本類型是無法泛型化的,所以它把int[] arr數(shù)組當(dāng)成了一個(gè)泛型對(duì)象,所以集合中最終只有一個(gè)元素arr。
錯(cuò)誤二
由于asList產(chǎn)生的集合元素是直接引用作為參數(shù)的數(shù)組,所以當(dāng)外部數(shù)組或集合改變時(shí),數(shù)組和集合會(huì)同步變化,這在平時(shí)我們編碼時(shí)可能產(chǎn)生莫名的問題。
錯(cuò)誤三
由于asList產(chǎn)生的集合并沒有重寫add,remove等方法,所以它會(huì)調(diào)用父類AbstractList的方法,而父類的方法中拋出的卻是異常信息。
5、支持基礎(chǔ)類型的方式
如果使用Spring
int[] a = {1,2,3};
List list = CollectionUtils.arrayToList(a);
System.out.println(list);
如果使用Java 8
int intArray[] = {1, 2, 3};
List<Integer> iList = Arrays.stream(intArray)
.boxed()
.collect(Collectors.toList());
System.out.println(iList);
6、數(shù)組轉(zhuǎn)ArrayList
遍歷轉(zhuǎn)換
Integer intArray[] = {1, 2, 3};
ArrayList<Integer> aList = new ArrayList<>();
for (Integer i: intArray){
aList.add(i);
}
顯然這種方式不夠優(yōu)雅!反正我不愿意使用。
使用工具類
上面方案不夠優(yōu)雅,那么這種相對(duì)來說優(yōu)雅一些。
List<String> list = new ArrayList(); Collections.addAll(list, "welcome", "to", "china");
你以為這種還不錯(cuò)?
too young too simple!
addAll()方法的實(shí)現(xiàn)就是用的上面遍歷的方式。
如果使用Java 8
既可以用于基本類型也可以返回想要的集合。
int intArray[] = {1, 2, 3};
List<Integer> iList = Arrays.stream(intArray)
.boxed()
.collect(Collectors.toList());
System.out.println(iList);
兩個(gè)集合類結(jié)合
將Arrays.asList返回的集合作為ArrayList的構(gòu)造參數(shù)
ArrayList arrayList = new ArrayList<>(Arrays.asList("welcome", "to", "china"));
7、最后
勿以點(diǎn)小而不聞!體現(xiàn)程序素養(yǎng)或許就在這些小地方,不要給自己或別人留坑。
那么這個(gè)知識(shí)點(diǎn),你get到了嗎?get到了,那來繼續(xù)關(guān)注我。沒get到?來來來,咱倆單獨(dú)聊聊。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
idea2023設(shè)置啟動(dòng)參數(shù)、單元測(cè)試啟動(dòng)參數(shù)
在使用IDEA進(jìn)行開發(fā)時(shí),我們可以通過設(shè)置一些啟動(dòng)參數(shù)來優(yōu)化開發(fā)環(huán)境的性能和體驗(yàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
Java實(shí)現(xiàn)調(diào)用接口API并返回?cái)?shù)據(jù)
這篇文章主要介紹了Java實(shí)現(xiàn)調(diào)用接口API并返回?cái)?shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
Java并發(fā)編程 interrupt()方法示例詳解
interrrupt()方法可以用來打斷正在運(yùn)行的線程,也可以打斷sleep()、wait()、join()情況下的線程,但是這些情況下被打斷線程的打斷標(biāo)記不同,這篇文章主要介紹了Java并發(fā)編程 interrupt()方法示例詳解,需要的朋友可以參考下2023-06-06
SpringBoot可視化接口開發(fā)工具magic-api的簡(jiǎn)單使用教程
作為Java后端開發(fā),平時(shí)開發(fā)API接口的時(shí)候經(jīng)常需要定義Controller、Service、Dao、Mapper、XML、VO等Java對(duì)象。有沒有什么辦法可以讓我們不寫這些代碼,直接操作數(shù)據(jù)庫生成API接口呢?今天給大家推薦一款工具magic-api,來幫我們實(shí)現(xiàn)這個(gè)小目標(biāo)!2021-06-06
java學(xué)習(xí)DongTai被動(dòng)型IAST工具部署過程
被動(dòng)型IAST被認(rèn)為是DevSecOps測(cè)試階段實(shí)現(xiàn)自動(dòng)化安全測(cè)試的最佳工具,而就在前幾天,洞態(tài)IAST正式開源了,這對(duì)于甲方構(gòu)建安全工具鏈來說,絕對(duì)是一個(gè)大利好2021-10-10
Mybatis-plus常見的坑@TableField不生效問題
這篇文章主要介紹了Mybatis-plus常見的坑@TableField不生效問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01

