Arrays
提供了asList()
方法,可以很方便地得到一个List
List<Integer> integers = Arrays.asList(1, 2, 3, 4);
在日常操作中,我们通常都会使用add
和remove
方法对List
的元素进行管理。如
integers.add(5);
integers.remove(1)
这时就出现了异常:java.lang.UnsupportedOperationException
探究
Arrays.asList()
源码注释如下,指出返回了一个定长的list
, 这个方法充当array
系列API和collection
系列API之间的桥梁。所以说,返回值,只是数组简单包装而成的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 中做了详细的解释:
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.
不过没有关系,我们可以用ArrayList
的构造方法,来创建一个新的ArrayList
,然后再进行增删操作。
Integer[] ints = {1, 2, 3, 4};
ArrayList<Integer> integers = new ArrayList<>(Arrays.asList(ints));
integers.add(5);
这样就OK啦~
且慢!Arrays.asList()
源码里返回的不就是ArrayList
本身吗,怎么会不能add
, remove
呢?
点击跳转到这个ArrayList
的定义, 发现原来ArrayList
是Arrays
的内部类,根本不是java.util.ArrayList
.
- 假ArrayList:
java.util.Arrays$ArrayList
- 真ArrayList:
java.util.ArrayList
Arrays.asList
Arrays.asList(T... a)
中返回的ArrayList
是Arrays
的内部类,继承了AbstractList
。所以说调用add
方法的时候,其实调用了父类AbstractList
的方法,方法源码如下:
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
直接抛出了异常,跟我们之前实践的情况一致。
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()的其他局限性
没错,还有坑。
asList()
的返回值List<?>
会指定一个认为最合适元素类型,这点会造成一定的困惑。如:Arrays.asList(1, 2, 3, 4)
得到的就是一个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
就会报错。
遇到这种情况,解决方法是,用Collection.addAll()
替代,或者手动指定类型(见例子代码)。