对java中ArrayList无参构造器扩容机制的理解

先将扩容机制的结论给出;

1无参构造器扩容机制:

        当使用无参构造器创建ArrayList对象时,初始容量为0,第一次添加时,则扩容为10,当再次扩容时则扩容为1.5倍(当前容量的1.5倍)。

我们首先看到ArrayList属性相关的源码:


    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

这里我们看到定义了两个空数组EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA,定义了一个数组elementData来存放数据,所以ArrayList的底层存储结构依然是数组。

1.先来分析无参构造器的扩容机制:

ArrayList无参构造器源码:

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

上面已经看到了DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空数组,所以无参构造器一开始将ArrayList定义容量为0.

然后当我们向ArrayList使用add方法添加元素,直接看add方法的源码:

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

ensureCapacityInternal是判断当前容量是否足够添加一个数据的一个方法,如果容量足够放下一个数据,就将这个数据e存放到elementData里。

这里 size + 1 的意思就是再放下一个数据的容量大小,size是原容量大小,+1即代表再放一个数据。

看到ensureCapacityInternal的源码:

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

ensureCapacityInternal方法又调用了calculateCapacity方法,并将存放数据的数组elementData和最小内存minCapacity传给此方法,此时的minCapacity即是 size + 1。

再接着看到calculateCapacity的源码:

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

DEFAULTCAPACITY_EMPTY_ELEMENTDATA是前面定义的空数组,这里判断存放数据的数组elementData是否是空数组。

如果为空就取DEFAULT_CAPACITY和minCapacity之间的最大值,DEFAULT_CAPACITY是一开始定义的整形变量为10,minCapacity对于size + 1,就是要添加下一个数据所需的最小容量。所以第一次扩容容量为10.

如果不为空就返回minCapacity。

然后我们回到上一个方法,继续看到ensureExplicitCapacity方法的源码:

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

此时的参数列表传入的minCapacity,如果是的一次扩容,则由上一个方法可知,返回的是10。

modCount用于记录修改的次数,防止有多个线程同时取修改它。

再看到判断所需要的容量减去现存放数据数组的长度,如果大于零表示当前存放数据的数组容量不够,则执行grow方法来扩容。

再看到grow方法源码:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

将数组的长度赋值给oldCapacity,再将oldCapacity的1.5倍赋值给newCapacity。所以当第一次到这时,oldCapacity为0,newCapacity也为0,而minCapacity由上面的方法返回的值是10.

再判断,如果newCapacity比minCapacity小的话,将minCapacity赋值给newCapacity,所以第一次扩容时,0 - 10 < 0, 所以将10赋值给了newCapacity,所以第一次扩容不是按1.5倍扩容,而是直接扩容为10.

执行完这个方法后,依次返回,最后回到add方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值