jdk 1.8 Arraylist自动扩容

以无参构造为例

第一步:调用add方法添加元素

public boolean add(E e) {

    ensureCapacityInternal(size + 1);  // 添加元素前先调用ensureCapacityInternal方法
    elementData[size++] = e;//添加对象时,size+1
    return true;
}

第二步:调用ensureCapacityInternal方法,设定好minCapacity的值

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //判断是否为空数组
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

当空数组添加第1个元素时,minCapacity=1,调用max()方法取出DEFAULT_CAPACITY和minCapacity的最大值 ,minCapacity变为DEFAULT_CAPACITY(默认大小10),调用ensureExplicitCapacity方法。

当添加第2个元素时,直接调用ensureExplicitCapacity方法。

第三步:调用ensureExplicitCapacity方法修改修改次数,并判断是否需要扩容

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;//修改次数加1

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);//调用扩容方法
}

当添加第1个元素时,此时的elementData.length=1(为空列表),minCapacity=10,所以minCapacity>elementData.length,会进入grow(minCapacity)方法(此时minCapacity=10)。

当添加第2个元素时,此时的minCapacity=2,此时elementData.length(即是容量)在添加第一个元素后扩容成10了,所以minCapacity<elementData.length,不会进入grow(minCapacity)方法,数组容量仍为10不变

所以当添加第3、4···到第10个元素时,依然不会执行grow方法,数组容量都为10。

当添加到第11个元素时,(minCapacity=11)>(elementData.length=10),所以进入grow(minCapacity)方法进行扩容。

第四步:调用grow方法进行扩容

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //通过位运算右移一位,相当于除以2,运算速度快,新容量扩大到原容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        //从minCapacity和newCapacity种取出一个较大值作为扩容后新数组的容量
        //这个if判断主要是针对添加第一个元素时使用,1.5倍的oldCapacity 还是为0,所以newCapacity为最小容量10
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        //如果新容量大于数组的最大size,进入hugeCapacity方法
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //最后将原来的数组和新的容量大小传入到copyOf方法中复制(先设定一个新容量大小的数组,把原数据放入其中即可)
    elementData = Arrays.copyOf(elementData, newCapacity);
}

当add第1个元素时,oldCapacity为0,第一个if成立,newCapacity=minCapacity=10;但是第二个if不成立,则不会进入hugeCapacity方法,数组容量为10,add方法中return true,size增为1。

当add第11个元素进入grow方法时,newCapacity为15,比minCapacity(为11)大,第一个if判断不成立。新容量没有大于数组最大size,不会进入hugeCapacity方法。数组容量扩为15,add方法中return true,size增为11。

第五步:如果新容量大于MAX_ARRAY_SIZE,进入hugeCapacity方法

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

猜你喜欢

转载自blog.csdn.net/ATadpole/article/details/81582819