拆行解码 Java 集合源码之 ArrayList

341 阅读6分钟

Java 集合源码解析系列:

ArrayList 特性

  • 数据结构:Object[],可动态扩容(新建数组的方式)
  • 允许元素为 Null。
  • 非线程安全。可使用 Collections.synchronizedList 包装为线程安全列表。
  • 支持随机访问,通过元素索引:RandomAccess 接口标识(无任何方法,仅做标识)。
    • Collections.binarySearch() 对于传入的接口,会判断是否实现了 RandomAccess。
  • 插入和删除元素的时间复杂度受元素位置的影响。

源码

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    /**
     * 默认容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空集合的内部结构,避免重复创建空数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 默认容量的初始空数组(无参构造函数)。相当于是懒加载的标志.
     * 注意: 1.7 是饿汉式, 构造时就构建出默认容量的数组
     * 下次扩容时,如果数组为该值,则至少扩容为默认容量。详细流程可见扩容
     * 注意是至少,如果指定扩容为 5,那还是会扩容为默认容量 10。
     * 不指定扩容,则默认 10。
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 存储ArrayList的元素的数组缓冲区。
     * ArrayList的容量是此数组缓冲区的长度。
     * 添加第一个元素时,任何具有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList都将扩展为DEFAULT_CAPACITY。
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * 实际添加的元素数量
     */
    private int size;

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            // 如果无容量,则设置为空数组。
            // 注意该值不受默认容量的限制
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }


    public ArrayList() {
        // 只有添加元素时才会开辟有容量的数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // defend against c.toArray (incorrectly) not returning Object[]
            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
            // 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            // 根据集合创建时, 如果原集合为空, 则容量为 0
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    /**
     * 将 数组长度 调整为 实际元素的数量
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

    /**
     * 元素搜索、元素判存、元素索引是依赖于 indexOfRange 和 lastIndexOfRange。
     * 前者正向,从前往后;后者逆向,从后往前。
     * 判断指定索引范围[start, end]内, 元素的索引位置.
     * 全局的话, start = 0, end = size (注意是实际元素长度,不是数组容量)。
     */
    int indexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {
            for (int i = start; i < end; i++) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = start; i < end; i++) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

    int lastIndexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {
            for (int i = end - 1; i >= start; i--) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = end - 1; i >= start; i--) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

    public int lastIndexOf(Object o) {
        return lastIndexOfRange(o, 0, size);
    }
    
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // 数组不够大, 基于类型新建一个足够分配的数组
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            // 如果数组长度过长, 则紧跟着最后一个元素的位置设置为空, 好让调用者判断元素有多少.
            a[size] = null;
        return a;
    } return oldValue;
    

    /**
     * 这个方法抽出来是为了 add 的字节码数量足够少, 来确保 C1 编译优化的循环内联
     */
    private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            // 注意, 没有空余的位置才去扩容
            // 说明数组自身不会预留空间。
            // ps: 如果批量插入很多元素时, 可以手动扩容, 预留空间:ensureCapacity
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

    public void add(int index, E element) {
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            // 扩容条件同上
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }

    public E remove(int index) {
        Objects.checkIndex(index, size);
        final Object[] es = elementData;

        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
        // 实际移除动作
        fastRemove(es, index);

        return oldValue;
    }

    /**
     * 如果集合类型不一致, 利用迭代器
     * 比较元素数量是否一致、元素的顺序是否一致、元素之间是否一致
     */
    boolean equalsRange(List<?> other, int from, int to) {
        final Object[] es = elementData;
        if (to > es.length) {
            throw new ConcurrentModificationException();
        }
        var oit = other.iterator();
        for (; from < to; from++) {
            if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) {
                return false;
            }
        }
        return !oit.hasNext();
    }

    /**
     * 类型一致, 可以利用数组快速比较
     */
    private boolean equalsArrayList(ArrayList<?> other) {
        final int otherModCount = other.modCount;
        final int s = size;
        boolean equal;
        if (equal = (s == other.size)) {
            final Object[] otherEs = other.elementData;
            final Object[] es = elementData;
            if (s > es.length || s > otherEs.length) {
                throw new ConcurrentModificationException();
            }
            for (int i = 0; i < s; i++) {
                if (!Objects.equals(es[i], otherEs[i])) {
                    equal = false;
                    break;
                }
            }
        }
        other.checkForComodification(otherModCount);
        return equal;
    }

    int hashCodeRange(int from, int to) {
        final Object[] es = elementData;
        if (to > es.length) {
            throw new ConcurrentModificationException();
        }
        int hashCode = 1;
        for (int i = from; i < to; i++) {
            Object e = es[i];
            // 计算所有元素的 hashcode, 减少冲突
            hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
        }
        return hashCode;
    }

    public boolean remove(Object o) {
        final Object[] es = elementData;
        final int size = this.size;
        int i = 0;
        // 从前往后, 删除第一个找到的
        found: {
            if (o == null) {
                for (; i < size; i++)
                    if (es[i] == null)
                        break found;
            } else {
                for (; i < size; i++)
                    if (o.equals(es[i]))
                        break found;
            }
            return false;
        }
        fastRemove(es, i);
        return true;
    }

    private void fastRemove(Object[] es, int i) {
        modCount++;
        final int newSize;
        if ((newSize = size - 1) > i)
            // 把 i+1 ~ size 移到 i ~ size -1
            // 将 size 置为 null
            System.arraycopy(es, i + 1, es, i, newSize - i);
        es[size = newSize] = null;
    }

    public void clear() {
        modCount++;
        final Object[] es = elementData;
        for (int to = size, i = size = 0; i < to; i++)
            es[i] = null;
    }

    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        modCount++;
        int numNew = a.length;
        if (numNew == 0)
            return false;
        Object[] elementData;
        final int s;
        // c 的长度大于 剩余空间, 则扩容的新容量为两个size 之和
        if (numNew > (elementData = this.elementData).length - (s = size))
            elementData = grow(s + numNew);
        System.arraycopy(a, 0, elementData, s, numNew);
        size = s + numNew;
        return true;
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        modCount++;
        int numNew = a.length;
        if (numNew == 0)
            return false;
        Object[] elementData;
        final int s;
        if (numNew > (elementData = this.elementData).length - (s = size))
            elementData = grow(s + numNew);

        int numMoved = s - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index,
                             elementData, index + numNew,
                             numMoved);
        System.arraycopy(a, 0, elementData, index, numNew);
        size = s + numNew;
        return true;
    }

    protected void removeRange(int fromIndex, int toIndex) {
        if (fromIndex > toIndex) {
            throw new IndexOutOfBoundsException(
                    outOfBoundsMsg(fromIndex, toIndex));
        }
        modCount++;
        shiftTailOverGap(elementData, fromIndex, toIndex);
    }

    /** Erases the gap from lo to hi, by sliding down following elements. */
    private void shiftTailOverGap(Object[] es, int lo, int hi) {
        // 先将后面的元素往前顺位, 再把后面空余的地方置为 null
        System.arraycopy(es, hi, es, lo, size - hi);
        for (int to = size, i = (size -= hi - lo); i < to; i++)
            es[i] = null;
    }

    boolean batchRemove(Collection<?> c, boolean complement,
                        final int from, final int end) {
        Objects.requireNonNull(c);
        final Object[] es = elementData;
        int r;
        // Optimize for initial run of survivors
        for (r = from;; r++) {
            if (r == end)
                return false;
            // 跳过不合法条件的前缀序列
            if (c.contains(es[r]) != complement)
                break;
        }
        int w = r++;
        try {
            for (Object e; r < end; r++)
                if (c.contains(e = es[r]) == complement)
                    es[w++] = e;
            // 数组:............w........r
        } catch (Throwable ex) {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            // 异常中断, 剩余未判断(r 之后)的元素不再处理, 顺位到 w 后面.
            // 数组:............w........r.....s
            System.arraycopy(es, r, es, w, end - r);
            // 数组:............r.....s..r.....s
            w += end - r;
            throw ex;
        } finally {
            modCount += end - w;
            shiftTailOverGap(es, w, end);
            // 正常分支:............w
            // 异常分支:............r.....s
        }
        return true;
    }
}

扩容

默认容量是10;默认扩容1.5倍

1.8 及以后,默认构造是单例空数组,只有第一次添加时才扩容。相当于是懒汉式加载

注意: 1.7 是饿汉式,

构造时就构建出默认容量的数组。

图中两个数值的比较在代码中其实都是通过减法比较的,避免 Integer 溢出的影响。 ArrayList扩容

    /**
     * 默认容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空集合的内部结构,避免重复创建空数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 默认容量的初始空数组(无参构造函数)。相当于是懒加载的标志.
     * 注意: 1.7 是饿汉式, 构造时就构建出默认容量的数组
     * 下次扩容时,如果数组为该值,则至少扩容为默认容量。详细流程可见扩容
     * 注意是至少,如果指定扩容为 5,那还是会扩容为默认容量 10。
     * 不指定扩容,则默认 10。
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 实际添加的元素数量
     */
    private int size;

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            // 如果无容量,则设置为空数组。
            // 注意该值不受默认容量的限制
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    public ArrayList() {
        // 只有添加元素时才会开辟有容量的数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // defend against c.toArray (incorrectly) not returning Object[]
            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
            // 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            // 根据集合创建时, 如果原集合为空, 则容量为 0
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    /**
     * 对外提供的扩容方法.
     * 在批量添加已知数量的元素时, 可以通过该方法提前且一次性扩容.
     * 避免多次扩容的时间损耗
     */
    public void ensureCapacity(int minCapacity) {
        // 两种情况, 不需要根据指定容量扩容
        // 1. 数组容量已满足
        // 2. 处于懒汉加载且指定容量小于默认容量. 因为懒加载的默认容量, 可以把它看做'已经开辟了默认容量的数组'.
        if (minCapacity > elementData.length
            && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
                 && minCapacity <= DEFAULT_CAPACITY)) {
            modCount++;
            grow(minCapacity);
        }
    }

    /**
     * 同 AbstractCollection
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 至少满足 minCapacity 的扩容,适合批量添加
     * 不过依旧受到默认规则的限制.比如 1.5 倍扩容, 默认容量, 最大容量等
     */
    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }

    /**
     * 适用于add, 至少满足容量 + 1.
     */
    private Object[] grow() {
        return grow(size + 1);
    }

    /**
     * 返回至少等于给定最小容量的容量。 如果足够,则返回增加50%的当前容量。
     * 除非给定的最小容量大于MAX_ARRAY_SIZE,否则不会返回大于MAX_ARRAY_SIZE的容量
     */
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 新容量默认为原来的 1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            // 因为是懒加载, 需要判断初始情况
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                // 懒加载下, 容量必定大于等于默认容量
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            //默认新容量不满足指定容量, 则按照指定容量
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
                // 1.5 扩容可能溢出了,重新根据 minCapacity 判断
            : hugeCapacity(minCapacity);
    }

    /**
     * 除非给定的最小容量大于MAX_ARRAY_SIZE,否则不会返回大于MAX_ARRAY_SIZE的容量
     */
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE
            : MAX_ARRAY_SIZE;
    }