ArrayList key method source code analysis

ArrayList

underlying structure

Object[] array, the size can be changed dynamically

Randomly accessible

Implemented the RandomAccess interface (an identification interface that identifies the interface that implements this class with random access function). The bottom layer is because the array storage method is continuously stored.

Expansion mechanism

oldCapacity+oldCapacity>>1=1.5*oldCapacity

Use fail-fast mechanism

During the traversal process, use the modCount variable to count the number of times the structure has changed. If the content changes during the traversal process, modCount will change. When using hasNext()/next() in an iterator, you will want to detect the value of modCount. If it changes, an exception will be thrown. But if it changes and it happens to be the same value, no exception will be thrown.

Not thread safe

Memory space usage

The waste of space in ArrayList is mainly reflected in the fact that a certain amount of space is reserved at the end of the list, because every time data is added, memory is allocated once. If not enough is allocated, a new memory needs to be opened and the existing data is copied as a whole. This changes It is very time-consuming. We must consider both space optimization and time optimization.

Key method analysis

Defined constants, variables and arrays

//序列号
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认长度
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 定义一个空数组,当用户指定ArrayList容量为0时,返回空数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {
    
    };

    /**
     * 一个空的数组实例。
     * 当用户没有指定ArrayList的容量时(调用无参构造函数),返回的空的数组
     * 当用户第一次添加元素的时候,该数组会扩容为默认大小->10
     *
     * 与EMPTY-ELEMENTDATA区别:该数组是默认返回的,而后者是指定容量为10的时候返回
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
    
    };

    /**
     * 用该数组保存数据,而数组的长度就是ArrayList的容量
     * 当第一次增加元素的时候,数组会扩容为默认大小->10
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * ArrayList的实际大小
     */
    private int size;

Construction method

/**
     * 构造一个空的初始容量大小的数组
     *
     * @param  initialCapacity  初始容量大小
     * @throws IllegalArgumentException  如果大小为负数,则抛出该异常
     */
    public ArrayList(int initialCapacity) {
    
    
        if (initialCapacity > 0) {
    
    
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
    
    
            //当初始容量指定为0的时候,返回该EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
    
    
            //否则,小于0抛异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                    initialCapacity);
        }
    }

    /**
     * 无参构造函数
     * 创建一个空的ArrayList,此时长度为0
     * 添加第一个元素的时候,扩容为10
     */
    public ArrayList() {
    
    
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 创建一个包含collection的ArrayList,按照顺序返回
     *
     * @param c 被放入数组的集合
     * @throws NullPointerException 如果集合为null会抛出的异常
     */
    public ArrayList(Collection<? extends E> c) {
    
    
        //将集合转换为数组
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
    
    
            //c.toArray可能不会返回Object[]
            if (elementData.getClass() != Object[].class)
                //如果返回的不是Object[]类型,用copyOf来创建一个大小为size的Object[]数组
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
    
    
            //换成空数组
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

Expansion mechanism

     /**
     * 数组缓冲区最大存储容量
     * 一些VM会在一个数组中存储某些数据
     * 为什么-8?
     * 尝试分配这个最大存储容量,可能会导致OutOfMemoryError(当该值大于VM的限制的时候)
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
    /**
     * 扩容,确保ArrayList至少能存储minCapacity个元素
     * 扩容计算:newCapacity=oldCapacity + (oldCapacity >> 1)=1.5 oldCapacity;
     * @param minCapacity 指定的最小容量
     */
    private void grow(int minCapacity) {
    
    
        int oldCapacity = elementData.length;
        //新容量大小
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //若newCapacity大于最大存储容量,则进行大容量分配
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 复制到新的数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

	/**
     * 大容量分配,最大分配Integer_MAX_VALUE
     * @param minCapacity   指定的最小容量
     * @return
     */
    private static int hugeCapacity(int minCapacity) {
    
    
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

clone

/**
     * 深度复制:对拷贝出来的ArrayList对象操作,不会影响原来的ArrayList
     *@return a clone of this <tt>ArrayList</tt> instance
     */
    public Object clone() {
    
    
        try {
    
    
            //Object的克隆方法:会复制本对象及其内所有基本类型成员和string类型成员,但不会复制对象成员、引用对象
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
    
    
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

toArray()

/**
     * 返回ArrayList的Object数组
     * 对返回的数组进行操作,不会影响被复制的ArrayList
     */
    public Object[] toArray() {
    
    
        return Arrays.copyOf(elementData, size);
    }

    /**
     * 返回ArrayList元素组成的数组
     * 若 a.length >= list.size,则将 list 中的元素按顺序存入 a 中,
     * 然后 a[list.size] = null, a[list.size + 1] 及其后的元素依旧是 a 的元素
     * @throws ArrayStoreException 当a.getClass()!=list中存储元素类型时
     * @throws NullPointerException 如果a为null
     */
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
    
    
        //如果数组a的大小<ArrayList的元素个数,则新建一个T[]数组,数组大小是ArrayList的元素个数
        //再把ArrayList全部拷贝到新数组中
        if (a.length < size)
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());

        //如果数组a的大小>=ArrayList的元素个数,则把ArrayList的全部元素拷贝到a中
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

get、set、remove、add

/**
     * 获得指定位置的元素
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
    
    
        //检查是否越界
        rangeCheck(index);

        return elementData(index);
    }

    /**
     * 将index位置的元素设置为element,返回原来index位置的值
     */
    public E set(int index, E element) {
    
    
        //数组越界检查
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

    /**
     * 添加元素
     */
    public boolean add(E e) {
    
    
        //注意:size+1,保证资源空间不被浪费,按当前情况,保证存多少个元素就分配多少内存
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    /**
     * 在index位置添加element,然后将该位置及其之后的元素往后移
     */
    public void add(int index, E element) {
    
    
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //将elementData从下标为Index位置开始的元素,拷贝到index+1位置,拷贝size-index个
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        elementData[index] = element;
        size++;
    }

    /**
     * 移除index位置的元素
     */
    public E remove(int index) {
    
    
        //检查是否越界
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);
        //需要左移的元素个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            // 将 elementData(源数组)从下标为 index+1 开始的元素,
            // 拷贝到 elementData(目标数组)下标为 index 的位置,总共拷贝 numMoved 个
            System.arraycopy(elementData, index+1, elementData, index,
                    numMoved);
        //将最后一个元素置空
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

    /**
     * 删除指定的某个元素,实际上还是调用的是remove(int index)
     */
    public boolean remove(Object o) {
    
    
        //先找个o的索引,再调用remove(int index)
        if (o == null) {
    
    
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
    
    
                    fastRemove(index);
                    return true;
                }
        } else {
    
    
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
    
    
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

    /*
     * 移除index位置上的元素
     */
    private void fastRemove(int index) {
    
    
        modCount++;
        //要移动的元素的个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //将index+1位置上的元素,移到index上,共移numMoved个
            System.arraycopy(elementData, index+1, elementData, index,
                    numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

    /**
     *移除数组中的所以元素
     * 清空后,打印list,只会看见[],而不是[null,null,null...],因为toString()和迭代器进行了处理
     */
    public void clear() {
    
    
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

    /**
     * 将一个集合的元素全部添加到数组的末尾
     *  该方法没有加锁,当一个线程正在将 c 中的元素加入 list 中,但同时有另一个线程在更改 c 中的元素,可能会有问题
     */
    public boolean addAll(Collection<? extends E> c) {
    
    
        Object[] a = c.toArray();
        //要添加的元素个数
        int numNew = a.length;
        //扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

    /**
     * 将c的全部元素添加到数组起始位置为index,但不会覆盖原来index的值
     */
    public boolean addAll(int index, Collection<? extends E> c) {
    
    
        //检查是否越界
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        //扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //需要移动元素的个数
        int numMoved = size - index;
        //先移动元素,再拷贝,以免被覆盖
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                    numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

    /**
     *移除fromIndex~toIndex范围内的元素
     */
    protected void removeRange(int fromIndex, int toIndex) {
    
    
        modCount++;
        int numMoved = size - toIndex;
        //将toIndex的元素移动到起始位置为fromIndex,移动numMoved个元素,左闭右开
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                numMoved);

        // 数组新的大小
        int newSize = size - (toIndex-fromIndex);
        //将newSize位置之后的元素全部置空
        for (int i = newSize; i < size; i++) {
    
    
            elementData[i] = null;
        }
        size = newSize;
    }

    /**
     * 提供给get()/remove()检查数组是否越界,如果越界则抛出异常
     */
    private void rangeCheck(int index) {
    
    
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * 提供给add()和add()进行数组越界检查的方法
     */
    private void rangeCheckForAdd(int index) {
    
    
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * 返回异常消息,IndexOutOfBoundsException
     */
    private String outOfBoundsMsg(int index) {
    
    
        return "Index: "+index+", Size: "+size;
    }

    /**
     *移除list和c中共有的元素
     */
    public boolean removeAll(Collection<?> c) {
    
    
        //如果c为null,则抛出空指针异常
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

    /**
     * 保留list和c中共有的元素
     */
    public boolean retainAll(Collection<?> c) {
    
    
        //如果c为null,则抛出空指针异常
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    /**
     *
     * @param c
     * @param complement 是否取补集
     * @return
     */
    private boolean batchRemove(Collection<?> c, boolean complement) {
    
    
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
    
    
            for (; r < size; r++)
                //如果c和elementData 都有/都没有 的元素
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
    
    
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
    
    
                System.arraycopy(elementData, r,
                        elementData, w,
                        size - r);
                w += size - r;
            }
            if (w != size) {
    
    
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

forEach

@Override
    public void forEach(Consumer<? super E> action) {
    
    
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        //在每次到下一个元素之前,会进行一次快速失败检查,看modCount是否改变
        for (int i=0; modCount == expectedModCount && i < size; i++) {
    
    
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
    
    
            throw new ConcurrentModificationException();
        }
    }

Iterator

/**
     * 返回一个Iterator迭代器,该迭代器是fail-fast机制
     */
    public Iterator<E> iterator() {
    
    
        return new Itr();
    }

    /**
     * AbstractList.Itr的优化版本
     */
    private class Itr implements Iterator<E> {
    
    
        int cursor;       // 下一个返回元素的索引,默认为0
        int lastRet = -1; // 上一个返回元素的索引,若没有上一个元素,则为-1.每次调用remove(),lastRet都会重置为-1
        int expectedModCount = modCount;

        //是否有下一个元素
        public boolean hasNext() {
    
    
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
    
    
            checkForComodification();
            //临时变量i,指向游标当前位置
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            //检查没有问题,则将cursor指向下一个
            cursor = i + 1;
            //将上一个指向当前
            return (E) elementData[lastRet = i];
        }

        public void remove() {
    
    
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
    
    
                //移除元素
                ArrayList.this.remove(lastRet);
                //回到上一个位置
                cursor = lastRet;
                //上一元素指针直接重置为-1.故lastRet不一定等于cursor-1
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
    
    
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
    
    
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
    
    
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
    
    
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
    
    
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        //快速失败检查机制,如果ModCount不是原来的值,则抛出异常
        final void checkForComodification() {
    
    
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

Guess you like

Origin blog.csdn.net/weixin_43589025/article/details/109577640