java 源碼分析Arrays.asList方法詳解
最近,抽空把java Arrays 工具類的asList 方法做了源碼分析,在網(wǎng)上整理了相關(guān)資料,記錄下來(lái),希望也能幫助讀者!
Arrays工具類提供了一個(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); }
問題發(fā)現(xiàn)
根據(jù)上述方法的描述,我們先來(lái)編寫幾個(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方法,竟然遇到問題。
原因查找
那么問題來(lái)了,到底發(fā)生了什么事情?帶著疑問,去查看一下Arrays.asList中使用的ArrayList到底長(zhǎng)啥樣?
原來(lái)Arrays的asList方法使用的ArrayList類是一個(gè)內(nèi)部定義的類,而不是java.util.ArrayList類。
其源代碼如下:
/** * @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)部類ArrayList的實(shí)現(xiàn)可以看出,它繼承了抽象類java.util.AbstractList<E>, 但是沒有重寫add和remove方法,沒有給出具體的實(shí)現(xiàn)。
但是,默認(rèn)情況下,java.util.AbstractList類在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類的內(nèi)部類ArrayList沒有重寫add和remove方法,所以,當(dāng)我們調(diào)用其add方法時(shí),其實(shí)就是調(diào)用了AbstractList類的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)部類ArrayList重寫了set方法,所以上述程序能夠正常運(yùn)行,不會(huì)再拋出UnsupportedOperationException異常。
結(jié)果如下:
[Welcome, to, Java, world]
[Welcome, to, hello, world]
使用場(chǎng)景
從上述的例子和簡(jiǎn)單分析來(lái)看,Arrays工具類提供了一個(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)文章
Java虛擬機(jī)JVM性能優(yōu)化(三):垃圾收集詳解
這篇文章主要介紹了Java虛擬機(jī)JVM性能優(yōu)化(三):垃圾收集詳解,本文講解了眾多的JVM垃圾收集器知識(shí)點(diǎn),需要的朋友可以參考下2014-09-09java輸入時(shí)如何通過回車(enter)來(lái)結(jié)束輸入
這篇文章主要介紹了java輸入時(shí)如何通過回車(enter)來(lái)結(jié)束輸入,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05談?wù)凧ava中try-catch-finally中的return語(yǔ)句
我們知道return語(yǔ)句用在某一個(gè)方法中,一是用于返回函數(shù)的執(zhí)行結(jié)果,二是用于返回值為void類型的函數(shù)中,僅僅是一個(gè)return語(yǔ)句(return ;),此時(shí)用于結(jié)束方法的執(zhí)行,也即此return后的語(yǔ)句將不會(huì)被執(zhí)行,當(dāng)然,這種情況下return語(yǔ)句后不能再有其它的語(yǔ)句了2016-01-01關(guān)于QueryWrapper,實(shí)現(xiàn)MybatisPlus多表關(guān)聯(lián)查詢方式
這篇文章主要介紹了關(guān)于QueryWrapper,實(shí)現(xiàn)MybatisPlus多表關(guān)聯(lián)查詢方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01Java中的NoClassDefFoundError報(bào)錯(cuò)含義解析
這篇文章主要為大家介紹了Java中的NoClassDefFoundError含義詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2023-11-11