聊聊Arrays.asList()踩过的那些坑

问题重现

日常开发中为了方便快捷的初始化一个List,经常会用到Arrays.asList()这个方法,不过有一次却出现了一个很奇怪的问题,测试代码如下:

    @Test
    public void test() {
    
    
        List<Integer> ids=Arrays.asList(1,2);
        ids.add(3);
    }

运行结果

java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(AbstractList.java:148)
	at java.util.AbstractList.add(AbstractList.java:108)
	at com.zjrb.media.media.MediaTest.test(MediaTest.java:36)

这一段代码是不是太平常不过了?初始化一个List,然后再向List里增加一个元素,为什么会报操作不支持的错误呢?看来Arrays.adList()还是有坑的,所以这里总结一下这些坑。

1. add()、remove()、add()、removeAll() … 等添加/删除方法不可用

    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.asList()的源码可以发现,方法返回的ArrayList 并不是 java.utill.ArrayList 而是 java.utill.arrays.ArrayList,而且存放数组变量是private final E[] a; ,这是个长度不可变的数组,所以List接口里的 add()、remove()、addAll()、removeAll()等增加、删除操作方法都不可用。当然修改数组中变量的值 set()方法还是可用的。

2. 不支持基本类型数组

测试代码如下

        int [] a={
    
    1,2};
        Integer [] b={
    
    1,2};
        System.out.println(Arrays.asList(a));
        System.out.println(Arrays.asList(b));

输出为:

[[I@cb29b75]
[1, 2]

因为public static <T> List<T> asList(T... a) 接收的参数是一个泛型T,基本类型不支持泛型,所以只能把int [] 数组当做一个引用参数,从而返回的List中只有一个值了,当然更不是你想要的值。

3. toArrays()方法返回数据类型不一样

java.utill.ArrayList测试代码:

        List<Integer> a=new ArrayList<>();
        a.add(1);
        Object [] objects=a.toArray();
        System.out.println(objects.getClass());
        //输出class [Ljava.lang.Object;

Arrays.asList()测试代码:

        List<Integer> a=Arrays.asList(1);
        Object [] objects=a.toArray();
        System.out.println(objects.getClass());
        //输出 class [Ljava.lang.Integer;

Arrays.asList toArray()源码:

        @Override
        public Object[] toArray() {
    
    
            return a.clone();
        }
  

这些返回的是 T[]a 的clone(),返回的类型还是Integer [],只是向上转成了Object[]。

java.utill.ArrayList toArray()源码:

       public Object[] toArray() {
    
    
        return Arrays.copyOf(elementData, size);
    }
    

java.utill.ArrayList toArray()返回的就是Object[]类型。所以实际使用时要注意了。

4. 添加后再修改原参数坑

java.util.ArrayList测试代码

        Integer [] a={
    
    1,2,3};
        List<Integer> list=new ArrayList<>();
        Collections.addAll(list,a);
        a[0]=4;
        System.out.println(list);
        //输出  [1,2,3]

Arrays.asList测试代码:

        Integer [] a={
    
    1,2,3};
        List<Integer> list=Arrays.asList(a);
        a[0]=4;
        System.out.println(list);
        //输出 [4, 2, 3]

Arrays.asList() 是调用a = Objects.requireNonNull(array); ,只是一个引用,所以修改原参数的值,数组中的值也会改变

总结

Arrays.asList() 目前发现这些坑,希望大家使用时要小心点,前人踩过的坑就不要再踩了。如果你还发现了其它坑欢迎交流分享!

猜你喜欢

转载自blog.csdn.net/whzhaochao/article/details/117252847