超详细的ArrayList扩容过程(配合源码详解)

首先,在调用add方法的时候 ,会去调用 ensureCapacityInternal 方法,传入一个参数 minCapacity 大小是size + 1,也就是现在我们需要的数组的最小的大小。
在ensureCapacityInternal 方法中,先判断一下elementdata是不是初始空数组
是的话就把minCapacity变更为默认容量 也就是10, 和传进来的minCapacity的最大值
之后调用 ensureExplicitCapacity 方法,把现在的minCapacity传进去

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

第二步:
在这个ensureExplicitCapacity 方法中,会去判断一下传进来的minCapacity和当前elementdata的大小,如果需要的这个最小容量已经超过了当前数组的长度,就会去调用grow方法,也就是扩容的核心方法,并且把这个minCapacity传进去

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

第三步:
进入grow方法后,先去获取现在的elementdata的长度,并且先行扩容到1.5倍(这个>>1是位运算)。扩容后的容量记为 newCapacity ,用这个newCapacity 去和minCapacity也就是我们需要的最小的大小进行比较,还是达不到的话就让newCapacity=minCapacity。接着还要处理一下当前的newCapacity超过MAX_ARRAY_SIZE,也就是ArrayList允许的数组最大值的情况(一般是Integer.MAX_VALUE - 8)。调用hugeCapacity来进行处理,小于0的话就抛异常,超过最大值了就取最大值。最后调用Arrays.copyOf()方法。

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容到原来的 1.5 倍
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity; // 若新容量仍不足,则取所需的最小容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity); // 检查是否超过最大允许大小
    elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError(); // 超出 int 最大值时抛出异常
    return (minCapacity > MAX_ARRAY_SIZE) ?
           Integer.MAX_VALUE : // 如果实际需求超大,则直接取 Integer.MAX_VALUE
           MAX_ARRAY_SIZE;     // 否则取最大允许的数组大小
}

最后在这个Arrays.copyOf()方法中会创建一个新的数组,大小就是我们上一步得到并且传入的newCapacity。接着把旧数组中的元素拷贝到新数组中。

public static <T> T[] copyOf(T[] original, int newLength) {
    T[] copy = (T[]) Array.newInstance(original.getClass().getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
    return copy;
}
posted @ 2024-11-19 20:35  loopyhz  阅读(74)  评论(0编辑  收藏  举报