java 源碼分析Arrays.asList方法詳解
最近,抽空把java Arrays 工具類(lèi)的asList 方法做了源碼分析,在網(wǎng)上整理了相關(guān)資料,記錄下來(lái),希望也能幫助讀者!
Arrays工具類(lèi)提供了一個(gè)方法asList, 使用該方法可以將一個(gè)變長(zhǎng)參數(shù)或者數(shù)組轉(zhuǎn)換成List 。
其源代碼如下:
/**
* Returns a fixed-size list backed by the specified array. (Changes to
* the returned list "write through" to the array.) This method acts
* as bridge between array-based and collection-based APIs, in
* combination with {@link Collection#toArray}. The returned list is
* serializable and implements {@link RandomAccess}.
*
* <p>This method also provides a convenient way to create a fixed-size
* list initialized to contain several elements:
* <pre>
* List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
* </pre>
*
* @param a the array by which the list will be backed
* @return a list view of the specified array
*/
@SafeVarargs
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
問(wèn)題發(fā)現(xiàn)
根據(jù)上述方法的描述,我們先來(lái)編寫(xiě)幾個(gè)例子:
/**
* @author wangmengjun
*
*/
public class ArrayExample {
public static void main(String[] args) {
/**使用變長(zhǎng)參數(shù)*/
List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
System.out.println(array1);
/**使用數(shù)組*/
List<String> array2 = Arrays.asList(new String[] {"Welcome", "to","Java", "world"});
System.out.println(array2);
}
}
運(yùn)行上述程序,輸出如下內(nèi)容。
[Welcome, to, Java, world]
[Welcome, to, Java, world]
心血來(lái)潮,突然想在創(chuàng)建的列表中添加一個(gè)字符串“Cool~~~”, 走一個(gè)。
/**使用變長(zhǎng)參數(shù)*/
List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
array1.add("Cool~~~");
結(jié)果,遇到一個(gè)UnsupportedOperationException異常:
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(Unknown Source) at java.util.AbstractList.add(Unknown Source) at test.ArrayExample.main(ArrayExample.java:36)
不可思議,new ArrayList<>(a)產(chǎn)生的列表調(diào)用add方法,竟然遇到問(wèn)題。
原因查找
那么問(wèn)題來(lái)了,到底發(fā)生了什么事情?帶著疑問(wèn),去查看一下Arrays.asList中使用的ArrayList到底長(zhǎng)啥樣?
原來(lái)Arrays的asList方法使用的ArrayList類(lèi)是一個(gè)內(nèi)部定義的類(lèi),而不是java.util.ArrayList類(lèi)。
其源代碼如下:
/**
* @serial include
*/
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;
}
public int size() {
return a.length;
}
public Object[] toArray() {
return a.clone();
}
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
public E get(int index) {
return a[index];
}
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
public int indexOf(Object o) {
if (o==null) {
for (int i=0; i<a.length; i++)
if (a[i]==null)
return i;
} else {
for (int i=0; i<a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
public boolean contains(Object o) {
return indexOf(o) != -1;
}
}
從這個(gè)內(nèi)部類(lèi)ArrayList的實(shí)現(xiàn)可以看出,它繼承了抽象類(lèi)java.util.AbstractList<E>, 但是沒(méi)有重寫(xiě)add和remove方法,沒(méi)有給出具體的實(shí)現(xiàn)。
但是,默認(rèn)情況下,java.util.AbstractList類(lèi)在add、set以及remove方法中,直接會(huì)拋出UnsupportedOperationException異常。AbstractList的部分源代碼如下:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected AbstractList() {
}
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*
* <p>This implementation always throws an
* {@code UnsupportedOperationException}.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*
* <p>This implementation always throws an
* {@code UnsupportedOperationException}.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
throw new UnsupportedOperationException();
}
}
正是因?yàn)?span style="color: #0000ff">java.util.Arrays類(lèi)的內(nèi)部類(lèi)ArrayList沒(méi)有重寫(xiě)add和remove方法,所以,當(dāng)我們調(diào)用其add方法時(shí),其實(shí)就是調(diào)用了AbstractList類(lèi)的add方法,結(jié)果就是直接拋出UnsupportedOperationException異常。
同理,在調(diào)用remove方法,或者調(diào)用與add、remove方法相關(guān)聯(lián)的其它方法(如addAll)同樣會(huì)遇到UnsupportedOperationException異常。
addAll的例子:
/**
* @author wangmengjun
*
*/
public class ArrayExample {
public static void main(String[] args) {
/**使用變長(zhǎng)參數(shù)*/
List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
array1.addAll(Arrays.asList("AAA", "BBB"));
}
}
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(Unknown Source) at java.util.AbstractList.add(Unknown Source) at java.util.AbstractCollection.addAll(Unknown Source) at test.ArrayExample.main(ArrayExample.java:36)
set的例子:
/**
* @author wangmengjun
*
*/
public class ArrayExample {
public static void main(String[] args) {
/**使用變長(zhǎng)參數(shù)*/
List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
System.out.println(array1);
//將Java替換成hello
array1.set(2, "hello");
System.out.println(array1);
}
}
正是由于Arrays的內(nèi)部類(lèi)ArrayList重寫(xiě)了set方法,所以上述程序能夠正常運(yùn)行,不會(huì)再拋出UnsupportedOperationException異常。
結(jié)果如下:
[Welcome, to, Java, world]
[Welcome, to, hello, world]
使用場(chǎng)景
從上述的例子和簡(jiǎn)單分析來(lái)看,Arrays工具類(lèi)提供了一個(gè)方法asList, 使用該方法可以將一個(gè)變長(zhǎng)參數(shù)或者數(shù)組轉(zhuǎn)換成List 。
但是,生成的List的長(zhǎng)度是固定的;能夠進(jìn)行修改操作(比如,修改某個(gè)位置的元素);不能執(zhí)行影響長(zhǎng)度的操作(如add、remove等操作)。會(huì)拋出UnsupportedOperationException異常。
Arrays.asList比較適合那些已經(jīng)有數(shù)組數(shù)據(jù)或者一些元素,而需要快速構(gòu)建一個(gè)List,只用于讀取操作,而不進(jìn)行添加或刪除操作的場(chǎng)景。
如果,想要根據(jù)已知數(shù)組數(shù)據(jù),快速獲取一個(gè)可進(jìn)行增刪改查的列表List,一個(gè)比較簡(jiǎn)單的方法如下:
重新使用java.util.ArrayList包裝一層。
/**
* @author wangmengjun
*
*/
public class ArrayExample {
public static void main(String[] args) {
/**使用變長(zhǎng)參數(shù)*/
List<String> array1 = new ArrayList<>(Arrays.asList("Welcome", "to", "Java", "world"));
System.out.println(array1);
array1.add("Cool~~~");
System.out.println(array1);
}
}
結(jié)果如下:
[Welcome, to, Java, world]
[Welcome, to, Java, world, Cool~~~]
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Springboot攔截器如何獲取@RequestBody參數(shù)
這篇文章主要介紹了Springboot攔截器如何獲取@RequestBody參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
MyBatis-Plus中MetaObjectHandler沒(méi)生效完美解決
在進(jìn)行測(cè)試時(shí)發(fā)現(xiàn)配置的MyMetaObjectHandler并沒(méi)有生效,本文主要介紹了MyBatis-Plus中MetaObjectHandler沒(méi)生效完美解決,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
Windows Zookeeper安裝過(guò)程及啟動(dòng)圖解
這篇文章主要介紹了Windows Zookeeper安裝過(guò)程及啟動(dòng)圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12
SpringMvc返回modelandview返回的頁(yè)面無(wú)法跳轉(zhuǎn)問(wèn)題及解決
這篇文章主要介紹了SpringMvc返回modelandview返回的頁(yè)面無(wú)法跳轉(zhuǎn)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
簡(jiǎn)單理解java泛型的本質(zhì)(非類(lèi)型擦除)
泛型在java中有很重要的地位,在面向?qū)ο缶幊碳案鞣N設(shè)計(jì)模式中有非常廣泛的應(yīng)用。泛型是參數(shù)化類(lèi)型的應(yīng)用,操作的數(shù)據(jù)類(lèi)型不限定于特定類(lèi)型,可以根據(jù)實(shí)際需要設(shè)置不同的數(shù)據(jù)類(lèi)型,以實(shí)現(xiàn)代碼復(fù)用。下面小編來(lái)簡(jiǎn)單講一講泛型2019-05-05
詳解springcloud 基于feign的服務(wù)接口的統(tǒng)一hystrix降級(jí)處理
這篇文章主要介紹了詳解springcloud 基于feign的服務(wù)接口的統(tǒng)一hystrix降級(jí)處理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-06-06

