那些年踩过的坑之Arrays.asList

155 阅读2分钟

简述

我们在开发过程中使用Arrays.asList()的原因无非是想将数组或一些元素转为集合,但有时候得到的集合并不一定是我们想要的那个集合。

我们在使用的时候,需要注意什么呢?

一、不能将基本数据类型做为Arrays.asList方法的参数

public class TestArraysAsList {
    public static void main(String[] args) {
        int data [] = {1,2,3,4,5};
        List list= Arrays.asList(data);
        System.out.println("列表中的元素数量是:"+list.size());
    }
}

运行结果:

1

显然不是我们想要的结果,我们来看一下Arrays.asList的方法说明:输入一个变长参数,返回一个固定长度的列表。看源码:

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

方法的入参是一个泛型变长参数,我们知道基本类型是不能泛型化的,也就是说8个基本类型不能作为泛型参数,要想作为泛型参数就必须使用其所对应的包装类型。所以说知道了原因,改起来也比较简单,将 int 替换成Integer就可以了。

二、Arrays.asList方法产生的List的对象不可更改

public class TestArraysAsList {
    public static void main(String[] args) {
        Integer data [] = {1,2,3,4,5};
        List list= Arrays.asList(data);
        list.add(6);
        System.out.println("列表中的元素数量是:"+list.size());
    }
}

运行结果:

Exception in thread "main" java.lang.UnsupportedOperationException
 at java.util.AbstractList.add(AbstractList.java:148)
 at java.util.AbstractList.add(AbstractList.java:108)
 at object.ArrayAsListTest.main(ArrayAsListTest.java:11)

咦?报错了,UnsupportedOperationException 不支持的操作,不支持add吗?看源码:

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}
// 从上面可以得知,直接new了一个ArrayList对象返回,再看下这个类,这个ArrayList是否跟我们常用的java.util.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);
        }

        @Override
        public int size() {
            return a.length;
        }
     // ……
}

这个ArrayList是一个静态私有内部类,除了Arrays能访问外,其它类都不能访问,这个类确实没有提供add()方法,那既然可以调用,应该就是父类AbstractList提供了,顺便看一眼:

 public boolean add(E e) {
     add(size(), e);
     return true;
 }
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

父类提供了,但是没有实现,直接抛出了一个异常,需要子类覆盖这个方法实现,但是ArrayList没有覆盖,所以不支持增加操作。

顺便看了下ArrayList支持的方法有:size()toArray()get()set()contains()indexOf()spliterator()sort()

三、原数组发生变化,使用ArrayList得到的list会同步变化

public class TestArraysAsList {
    public static void main(String[] args) {
        Integer data [] = {1,2,3,4,5};
        data[0] = 0;
        List list= Arrays.asList(data);
      
        System.out.println("数组data[0]:"+data[0]);
        System.out.println("list(0):"+list.get(0));
    }
}

运行结果:

数组data[0]:0
list(0):0

结果是一样的,为啥呢?看源码:

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

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

Arrays.ArrayList将外部数组的引用直接通过“=”赋予内部的泛型数组,所以本质指向同一个数组。所以说如果真有这样的场景,还需要将转化过来的list,重新new ArrayList(list);一下就可以了。

有任何问题欢迎微信搜索【Hugh的白板】私信我,一起探讨,一起学习