Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arrays.asList踩坑记及源码分析 #19

Open
vonzhou opened this issue Jan 1, 2020 · 0 comments
Open

Arrays.asList踩坑记及源码分析 #19

vonzhou opened this issue Jan 1, 2020 · 0 comments

Comments

@vonzhou
Copy link
Owner

vonzhou commented Jan 1, 2020

最近在使用Arrays.asList时又犯了一个低级的错误导致了运行时异常,所以有必要把这个点好好理解下。从踩过的2个坑开始分析。

image

踩过的2个坑

Arrays.asList列表转数组问题

详细可以看这篇文章,toArray 方法返回的依然是 Object[],但是与 java.util.ArrayList 不同的是这里底层存储是泛型类型的数组 privatefinalE[]a,所以保留了实际的类型。

Arrays.asList列表不能新增元素

Arrays.asList构造的是一个固定大小的列表,底层存储是泛型数组,不能新增元素,原因在后面源码分析部分会看到。

Arrays.asList列表源码分析

Arrays.asList返回的是一个Arrays的内部类ArrayList,很小巧。

image

其实这个内部类和java.util.ArrayList的外貌(类层次图)是一样的,只是实现不同而已。
image

接下来我们分析内部类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) {// !! 支持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);
        }
    }

存储

使用泛型数组,并且原始数组不能为Null。

private final E[] a;

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

转换为数组

直接对数组a进行clone,所以保留了原始对象类型。

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

java.util.ArrayList一样,如果使用带指定参数类型的toArray就不存在返回类型不匹配的问题。

新增元素

该实现没有覆写add方法,而自AbstractList继承而来的add方法默认会抛出UnsupportedOperationException.

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

Java8新特性的支持

  • 列表分隔 Spliterator
  • 迭代遍历消费 Consumer
  • 使用一元操作符替换列表 UnaryOperator

总结及想法

  • 遇到问题要善于总结,不放过任何一个学习的机会
  • 直接问Arrays.asList特点可能知道,但是实际中可能不会注意,不思考状态下的编程不可取
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant