使用Arrays.asList注意事项

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,如果后面可能会改变,慎用该方法.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值