ArrayList扩容

1,284 阅读2分钟

​ 在执行 add 方法的时候如果碰到了存储单元不够用的情况才需要扩容. add 方法的第一行有一个 modCount,与扩容机制无关,暂且忽略他.

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

​ 继续向下,我们来到了下边这个方法:

private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)
        elementData = grow();
    elementData[s] = e;
    size = s + 1;
}

​ 这个方法有三个参数,分别是待添加的元素 , 对象数组, 添加元素之前数组的大小. 由第一个 if 可知,如果对象数组的长度等于了arrayList中实际包含的元素个数,就需要进行扩容了. 否则直接将元素存进去即可.

​ 继续向下,进入 grow方法:

private Object[] grow() {
    return grow(size + 1);
}
private Object[] grow(int minCapacity) {
    int oldCapacity = elementData.length;
    
    if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        int newCapacity = ArraysSupport.newLength(
            	oldCapacity,
                minCapacity - oldCapacity, /* minimum growth */
                oldCapacity >> 1           /* preferred growth */);
        
        return elementData = Arrays.copyOf(elementData, newCapacity);
    } else {
        return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
    }
}

​ 从上边可以看出 , 这一步通过调用 ArraysSupport.newLength 方法获得了扩容后的数组大小.

public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
    // assert oldLength >= 0
    // assert minGrowth > 0

    int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
    
    if (newLength - MAX_ARRAY_LENGTH <= 0) {
        return newLength;
    }
    return hugeLength(oldLength, minGrowth);
}

​ 在不超过最大数组容量的情况下,新的数组长度在原有的基础上增加了 max(minGrowth, prefGrowth).

层层分析 minGrowth在正常情况下恒为 ==1== . 绝大多处情况下, Math.max(minGrowth, prefGrowth)都等于

prefGrowth,只有在初始化ArrayList时初始容量为1第一次扩容时 , prefGrowth为 0 .

​ 当由上述算法得出的新的数组长度不超过MAX_ARRAY_LENGTH 时,扩容成功 . 如果超过了,则进入下一个方法 :

private static int hugeLength(int oldLength, int minGrowth) {
    int minLength = oldLength + minGrowth;
    if (minLength < 0) { // overflow
        throw new OutOfMemoryError("Required array length too large");
    }
    if (minLength <= MAX_ARRAY_LENGTH) {
        return MAX_ARRAY_LENGTH;
    }
    return Integer.MAX_VALUE;
}

​ 如果扩容后的数组大小超过 Integer.MAX_VALUE,直接抛出 ==OOM== 错误.

​ 如果扩容后的数组大小不超过 MAX_ARRAY_LENGTH , 则将MAX_ARRAY_LENGTH作为扩容后的数组大小

​ 如果扩容后的数组大小超过了MAX_ARRAY_LENGTH但未超过 Integer.MAX_VALUE,则将 Integer.MAX_VALUE作为扩

容后的数组大小.


​ 至此,扩容完成.