使用Arrays.asList注意事项

来源:互联网 发布:淘宝售假申诉补充留言 编辑:程序博客网 时间:2024/05/18 13:31

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

奇怪的地方有两点:

  1. int[] a没有正确地转化想要的list
  2. 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));

结论

  1. 基本类型不能作为泛型参数传入.如果需要,改成对应的包装类
  2. Arrays.asList返回的是固定只读的ArrayList,如果后面可能会改变,慎用该方法.
原创粉丝点击