【JAVA】谈谈Arrays.asList()

我们在日常的开发中,常常使用到Arrays.asList()这个方法,它能够很轻易地将一个数组转化为一个List。

例如:

    Integer[] a = new Integer[]{1, 2, 3};
    List<Integer> list = Arrays.asList(a);

现在已经是一个List了,我想对这个List做一些基本操作。

    list.add(4);

运行这段语句后,居然出现了java.lang.UnsupportedOperationException,什么情况,不支持这个新增操作吗?进到源码里,一探究竟。

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

不就是返回了一个ArrayList吗?ArrayList什么时候不支持add方法了,再点进这个“ArrayList”里

private static class ArrayList<E> extends AbstractList<E>
    implements RandomAccess, java.io.Serializable
{
    private static final long serialVersionUID = -2764017481108945198L;
    private final E[] a;

    ArrayList(E[] array) {
        a = Objects.requireNonNull(array);
    }
...
}

哦,原来此“ArrayList”不是我们经常用到的那个ArrayList,这个只是Arrays的一个内部类而已。此外,这个“ArrayList”继承AbstractList,却并没有重写它的set、add、remove方法,AbstractList源码如下所示。

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();
}

还有一个很重要的一点就是,这个“ArrayList”的构造方法,对传进来的数组没有做任何处理,仅仅是直接使用。那么,我们改变原数组中某个索引下标的元素,“ArrayList”也会做同样的改变。

好,既然这个“ArrayList”仅仅支持集合常用的get方法,那现在看这个例子,这一次我使用基本数据类型的数组。

    int[] a = new int[]{1, 2, 3};
    List list = Arrays.asList(a);
    System.out.println(list.get(0));
    System.out.println(list.get(1));

直接运行后,就报出了如下的错误

[I@1b6d3586
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at java.util.Arrays$ArrayList.get(Arrays.java:3841)
at com.yang.testList.Main.main(Main.java:12)

看的出来,这个“ArrayList”第一个元素输出是一个地址,尝试获取第二个元素时,直接就越界了。

原来啊,这个Arrays.asList()方法是一个泛型方法,需要的是一个对象类型的数组,而不是一个基本数据类型的数组。现在我们直接传入基本数据类型的数组,这个“ArrayList”的构造方法无法将基本类型的数组传到参数E[] a中,只能将一整个数组当作E[] a的第一个元素,因此get(0)时,获取到了这个基本数据类型数组的地址首值,而get(1)时,直接产生了越界异常。

看来,Arrays.asList坑挺多啊,那么,有什么其他方法能够将数组转为List呢?

(1)将Arrays.asList()构造出来的“ArrayList”传入java.util.ArrayList的构造方法里。

    Integer[] a = new Integer[]{1, 2, 3};
    List list = Arrays.asList(a);
    ArrayList arrayList = new ArrayList<>(list);

这个构造方法使用 Arrays.copyOf方法,因此java.util.ArrayList内部的数组和传入的数组将不会有任何的关系。关于数组复制效率的问题,可以参考我的另外一篇文章【JAVA】数组复制效率的比较

(2)使用stream

    Integer[] a = new Integer[]{1, 2, 3};
    List<Integer> collect = Arrays.stream(a).collect(Collectors.toList());

基本数据类型,可以先转化为Stream,再进行装箱即可。

    int[] b = new int[]{1, 2, 3};
    List<Integer> list = Arrays.stream(b).boxed().collect(Collectors.toList());

不过,使用stream进行转换,可能涉及效率问题,这篇文章暂不考虑。

(3)使用Guava

如果说,需要一个不可变集合,可以使用ImmutableList.copyOf方法

    Integer[] a = new Integer[]{1, 2, 3};
    List<Integer> list = ImmutableList.copyOf(a);

可变集合,可以使用Lists.newArrayList方法

    Integer[] a = new Integer[]{1, 2, 3};
    List<Integer> list = Lists.newArrayList(a);
全部评论
更多博客https://blog.csdn.net/qq_33591903
点赞 回复
分享
发布于 2020-04-01 17:11

相关推荐

头像
不愿透露姓名的神秘牛友
04-29 12:10
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务