Arrays
提供了asList()
方法,可以很方便地得到一個(gè)List
List<Integer> integers = Arrays.asList(1, 2, 3, 4);
在日常操作中,我們通常都會使用add
和remove
方法對List
的元素進(jìn)行管理。如
integers.add(5);
integers.remove(1)
這時(shí)就出現(xiàn)了異常:java.lang.UnsupportedOperationException
探究
Arrays.asList()
源碼注釋如下,指出返回了一個(gè)定長的list
, 這個(gè)方法充當(dāng)array
系列API和collection
系列API之間的橋梁。所以說,返回值,只是數(shù)組簡單包裝而成的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 <T> the class of the objects in the array
* @param a the array by which the list will be backed
* @return a list view of the specified array
*/
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
Think In Java 中做了詳細(xì)的解釋:
It’s also possible to use the output of Arrays.asList( ) directly, as a List, but the underlying representation in this case is the array, which cannot be resized. If you try to add( ) or delete( ) elements in such a list, that would attempt to change the size of an array, so you’ll get an "Unsupported Operation" error at run time.
不過沒有關(guān)系,我們可以用ArrayList
的構(gòu)造方法,來創(chuàng)建一個(gè)新的ArrayList
,然后再進(jìn)行增刪操作。
Integer[] ints = {1, 2, 3, 4};
ArrayList<Integer> integers = new ArrayList<>(Arrays.asList(ints));
integers.add(5);
這樣就OK啦~
且慢!Arrays.asList()
源碼里返回的不就是ArrayList
本身嗎,怎么會不能add
, remove
呢?
點(diǎn)擊跳轉(zhuǎn)到這個(gè)ArrayList
的定義, 發(fā)現(xiàn)原來ArrayList
是Arrays
的內(nèi)部類,根本不是java.util.ArrayList
.
- 假ArrayList:
java.util.Arrays$ArrayList
- 真ArrayList:
java.util.ArrayList
Arrays.asList
Arrays.asList(T... a)
中返回的ArrayList
是Arrays
的內(nèi)部類,繼承了AbstractList
。所以說調(diào)用add
方法的時(shí)候,其實(shí)調(diào)用了父類AbstractList
的方法,方法源碼如下:
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
直接拋出了異常,跟我們之前實(shí)踐的情況一致。
ArrayList
我們通常用的ArrayList
,繼承了AbstractList
,并重寫了add
, remove
等方法,源碼如下:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public E remove(int index) {
rangeCheck(index)
modCount++;
E oldValue = elementData(index)
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its wor
return oldValue;
}
Arrays.asList()的其他局限性
沒錯(cuò),還有坑。
asList()
的返回值List<?>
會指定一個(gè)認(rèn)為最合適元素類型,這點(diǎn)會造成一定的困惑。如:Arrays.asList(1, 2, 3, 4)
得到的就是一個(gè)List<Integer>
. Think In Java 中的例子如下:
//: holding/AsListInference.java
// Arrays.asList() makes its best guess about type.
import java.util.*;
class Snow {}
class Powder extends Snow {}
class Light extends Powder {}
class Heavy extends Powder {}
class Crusty extends Snow {}
class Slush extends Snow {}
public class AsListInference {
public static void main(String[] args) {
List<Snow> snow1 = Arrays.asList(new Crusty(), new Slush(), new Powder());
// Won’t compile:
// List<Snow> snow2 = Arrays.asList(new Light(), new Heavy());
// Compiler says:
// found : java.util.List<Powder>
// required: java.util.List<Snow>
// Collections.addAll() doesn’t get confused:
List<Snow> snow3 = new ArrayList<Snow>();
Collections.addAll(snow3, new Light(), new Heavy());
// Give a hint using an explicit type argument specification:
List<Snow> snow4 = Arrays.<Snow>asList(new Light(), new Heavy());
}
} ///:~
Arrays.asList(new Light(), new Heavy())
返回值為List<Power>
, 把它賦值給類型為List<Snow>
的snow2
就會報(bào)錯(cuò)。
遇到這種情況,解決方法是,用Collection.addAll()
替代,或者手動指定類型(見例子代碼)。