java Arrays.asList()

2020-08-14  本文已影响0人  王兴岭

在Java中比如想把一个数组转成集合,通常习惯使用Arrays.asList,但是要小心,数组通过Arrays.asList转成集合后,是不能调用集合的add,remove方法的.不然会抛异常UnsupportedOperationException,

Demo

    Integer[] array = {1, 2};
    List<Object> list = Arrays.asList(array);
    list.remove(1);

控制台结果

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.remove(AbstractList.java:161)
    at com.study.webfluxstudy.ArrayListTest.main(ArrayListTest.java:19)

如果新人第一次碰到这个问题可能会感觉很奇怪,add,remove方法不应该是集合的标配吗,怎么会不支持呢?分析下底层源码就知道了

/**
     * Returns a fixed-size list backed by the specified array.
    */
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

Returns a fixed-size list backed by the specified array.很关键的一句话,asList返回的list是固定大小的,那也就是说生成后的集合就不能再添加删除了,也就是不能add,remove了.注释虽然是这么说,但是如果看方法体中的代码,return new ArrayList<>(a),是不是更奇怪了.ArrayList大家在项目中常用的集合类,add,remove没问题啊.是什么原因呢?
阅读源码其实就能发现此ArrayList不是彼ArrayList.
asList静态方法中的ArrayList是Lists中的一个私有静态类,而不是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;
        }

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

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }

        @Override
        public E get(int index) {
            return a[index];
        }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

        @Override
        public int indexOf(Object o) {
            E[] a = this.a;
            if (o == null) {
                for (int i = 0; i < a.length; i++)
                    if (a[i] == null)
                        return i;
            } else {
                for (int i = 0; i < a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

        @Override
        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }

        @Override
        public Spliterator<E> spliterator() {
            return Spliterators.spliterator(a, Spliterator.ORDERED);
        }

        @Override
        public void forEach(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            for (E e : a) {
                action.accept(e);
            }
        }

        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            Objects.requireNonNull(operator);
            E[] a = this.a;
            for (int i = 0; i < a.length; i++) {
                a[i] = operator.apply(a[i]);
            }
        }

        @Override
        public void sort(Comparator<? super E> c) {
            Arrays.sort(a, c);
        }
    }

    public static int hashCode(long a[]) {
        if (a == null)
            return 0;

        int result = 1;
        for (long element : a) {
            int elementHash = (int)(element ^ (element >>> 32));
            result = 31 * result + elementHash;
        }

        return result;
    }

通过上面的源码可以看到起没有提供add,remove方法的实现,那调用add,remove其实是调用父类的方法

AbstractList

    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    public E remove(int index) {
        throw new UnsupportedOperationException();
    }

所以也就能解释为什么Demo演示代码调用add方法,在控制台会抛出UnsupportedOperationException异常了

如果让Arrays.asList()返回的集合支持add,remove方法

如果想实现这个目的需要借助java.util.ArrayList帮忙

public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

调整后的Demo

    Integer[] array = {1, 2};
    // 通过Arrays转换成的List,保留了原本的类型
    List<Integer> list = Arrays.asList(array);
    System.out.println(list);
    ArrayList<Integer> objects = new ArrayList<Integer>(list);
    objects.add(3);
    System.out.println(objects);

控制台输出

[1, 2]
[1, 2, 3]
上一篇下一篇

猜你喜欢

热点阅读