正确认识Arrays.asList方法
Arrays工具類提供了一個方法asList, 使用該方法可以將一個變長參數或者數組轉換成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*/public static <T> List<T> asList(T... a) {return new ArrayList<>(a);}?
問題發現
根據上述方法的描述,我們先來編寫幾個例子:
/*** @author wangmengjun**/ public class ArrayExample {public static void main(String[] args) {/**使用變長參數*/List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");System.out.println(array1);/**使用數組*/List<String> array2 = Arrays.asList(new String[] {"Welcome", "to","Java", "world"});System.out.println(array2);}}?
運行上述程序,輸出如下內容。
[Welcome, to, Java, world] [Welcome, to, Java, world]?
心血來潮,突然想在創建的列表中添加一個字符串“Cool~~~”, ?走一個。
/**使用變長參數*/List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");array1.add("Cool~~~");結果,遇到一個UnsupportedOperationException異常:
Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.util.AbstractList.add(Unknown Source)at java.util.AbstractList.add(Unknown Source)at test.ArrayExample.main(ArrayExample.java:36)不可思議,new ArrayList<>(a)產生的列表調用add方法,竟然遇到問題。
原因查找
那么問題來了,到底發生了什么事情?帶著疑問,去查看一下Arrays.asList中使用的ArrayList到底長啥樣?
原來Arrays的asList方法使用的ArrayList類是一個內部定義的類,而不是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;}}?
從這個內部類ArrayList的實現可以看出,它繼承了抽象類java.util.AbstractList<E>, 但是沒有重寫add和remove方法,沒有給出具體的實現。
但是,默認情況下,java.util.AbstractList類在add、set以及remove方法中,直接會拋出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();} }?
正是因為java.util.Arrays類的內部類ArrayList沒有重寫add和remove方法,所以,當我們調用其add方法時,其實就是調用了AbstractList類的add方法,結果就是直接拋出UnsupportedOperationException異常。
同理,在調用remove方法,或者調用與add、remove方法相關聯的其它方法(如addAll)同樣會遇到UnsupportedOperationException異常。
addAll的例子:
/*** @author wangmengjun**/ public class ArrayExample {public static void main(String[] args) {/**使用變長參數*/List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");array1.addAll(Arrays.asList("AAA", "BBB"));}}?
Exception in thread "main" java.lang.UnsupportedOperationExceptionat 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) {/**使用變長參數*/List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");System.out.println(array1);//將Java替換成helloarray1.set(2, "hello");System.out.println(array1);}}正是由于Arrays的內部類ArrayList重寫了set方法,所以上述程序能夠正常運行,不會再拋出UnsupportedOperationException異常。
結果如下:
[Welcome, to, Java, world] [Welcome, to, hello, world]?
使用場景
從上述的例子和簡單分析來看,Arrays工具類提供了一個方法asList, 使用該方法可以將一個變長參數或者數組轉換成List?。
但是,生成的List的長度是固定的;能夠進行修改操作(比如,修改某個位置的元素);不能執行影響長度的操作(如add、remove等操作)。會拋出UnsupportedOperationException異常。
Arrays.asList比較適合那些已經有數組數據或者一些元素,而需要快速構建一個List,只用于讀取操作,而不進行添加或刪除操作的場景。
如果,想要根據已知數組數據,快速獲取一個可進行增刪改查的列表List,一個比較簡單的方法如下:
重新使用java.util.ArrayList包裝一層。
/*** @author wangmengjun**/ public class ArrayExample {public static void main(String[] args) {/**使用變長參數*/List<String> array1 = new ArrayList<>(Arrays.asList("Welcome", "to", "Java", "world"));System.out.println(array1);array1.add("Cool~~~");System.out.println(array1);}}結果如下:
[Welcome, to, Java, world][Welcome, to, Java, world, Cool~~~]
from:?https://my.oschina.net/wangmengjun/blog/760998
總結
以上是生活随笔為你收集整理的正确认识Arrays.asList方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: REST 在 Java 中的使用
- 下一篇: 最简实例说明wait、notify、no