Arrays.asList()
方法将数组转成list,是java.util.Arrays类的静态方法。能够很方便地将数组转为List.该方法和Collection
接口的toArray()
方法,组成了基于数组与基于Collection的API之间互相转化的桥梁.
用一小段代码做个实验:
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
Integer[] b = {1, 2, 3, 4, 5};
String[] c = {"a", "b", "c"};
System.out.println(Arrays.asList(a));
System.out.println(Arrays.asList(b));
System.out.println(Arrays.asList(c));
List<String> list = Arrays.asList(c);
list.add("d");
System.out.println(list);
}
这段代码看起来不会有任何问题,但是实际呢?
看下输出的结果
[[I@7217fef]
[1, 2, 3, 4, 5]
[a, b, c]
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at com.zhuhengwei.ArraysTest.main(ArraysTest.java:22)
Process finished with exit code 1
奇怪的地方有两点:
- int[] a没有正确地转化想要的list
- list.add(“d”)抛出了
UnsupportedOperationException
异常
下面通过源码解释下出现的情况
问题1:int[] a没有正确转为list
首先看下方法声明
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
乍一看,很正常,没什么问题.
分析1:
asList(T…a)方法参数是一个泛型可变参数,而泛型的类型参数只能是类类型(包括自定义类),不能是基本数据类型.将int[] a基本类型的数组传入时,解释器将整个数组作为了可变参数的一个元素.
所以此时a ={int[1][]@…},是一个二维数组,所以转换后的list中只有一个元素,且元素是一个数组.基本类型是不能泛型化的,要想作为泛型参数就必须使用对应的包装类型。
问题2: 方法返回的是ArrayList,调用add()
为什么会报出异常呢?
分析2: 此ArrayList非彼ArrayList,它是Arrays中的静态私有内部类.
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private final E[] a;
ArrayList(E[] array) {
if (array==null)
throw new NullPointerException();
a = array;
}
}
该内部类ArrayList没有覆写add,remove等方法,这些方法由AbstractList提供.而且数组E[]为final类型.
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
这些方法均抛出UnsupportedOperationException
异常,所以问题就在于此.
在Arrays.asList方法上的doc上清楚地写着:该方法返回固定大小的list.而且E[]为final,所以是只读的.
Returns a fixed-size list backed by the specified array.
原因在于内部类只继承了AbstractList,而没有覆写add,remove等能够改变list容量的方法.在AbstractList类上方的doc中也有说明.
To implement an unmodifiable list, the programmer needs only to extend
this class and provide implementations for the {@link #get(int)} and
{@link List#size() size()} methods.
To implement a modifiable list, the programmer must additionally
override the {@link #set(int, Object) set(int, E)} method (which otherwise
throws an {@code UnsupportedOperationException}). If the list is
variable-size the programmer must additionally override the
{@link #add(int, Object) add(int, E)} and {@link #remove(int)} methods.
实现一个不可变list,只需要继承AbstractList,提供get()
和size()
方法;要实现可修改list,必须覆写set()
;要实现动态增删元素的list,必须覆写add()
等方法.
而我们经常用到的ArrayList正是这样做的,自己实现了add,romove等方法.
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{...}
那么如何解决UnsupportedOperationException
的问题呢?转为常用的java.util.ArrayList
.
List<String> list = new ArrayList<String>(Arrays.asList(c));
结论
- 基本类型不能作为泛型参数传入.如果需要,改成对应的包装类
- Arrays.asList返回的是固定只读的ArrayList,如果后面可能会改变,慎用该方法.