java的ArrayList动态扩容机制(JDK8)

要了解ArrayList的动态扩容机制,查看了解ArrayList中的add方法是必不可少的,add方法源码如下:

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

其中 ensureCapacityInternal(size + 1); 便是ArrayList的动态扩容机制,ensureCapacityInternal方法源码如下:

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

ensureCapacityInternal方法依靠调用ensureExplicitCapacity 方法实现动态扩容,在调用ensureExplicitCapacity 方法之前,java还调用了calculateCapacity(elementData, minCapacity),下面将逐一分析,首先看calculateCapacity(elementData, minCapacity)里面都做了什么吧。

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

先看入参,其中elementData便是ArrayList真正用于存储元素的数组,minCapacity代表elementData数组的新长度(原数组长度+要增加的数组长度),add方法意在ArrayList尾部加入新元素,那么此时ArrayList的minCapacity便是size+1,其中size表示此ArrayList实际存储数据元素的个数。
calculateCapacity 方法判断ArrayList默认的元素存储数据是否为空,其中DEFAULTCAPACITY_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 = {};

如果elementData为空,则返回传入的minCapacityDEFAULT_CAPACITY中的最大值,其中DEFAULT_CAPACITYelementData数组的默认长度:

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

如果elementData不为空,则返回传入的minCapacity;以上便是calculateCapacity 执行的完整过程。
总结如下
calculateCapacity方法完成了一件事,如果当前ArrayList存储数据元素的数组为空,则表示当前ArrayList可能为初始的ArrayList(未加入数据),此时只需返回默认的elementData数组的长度与你希望的数组新长度的较大值(因为ArrayList扩容是有性能损耗的,所以扩容的大小在合理范围内越大,将来扩容的次数就越小),如果此时ArrayList的elementData不为空,则直接返回你希望的数组新长度即可,calculateCapacity方法的返回值记为数组实际的新长度

然后我们在分析ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))方法,ensureExplicitCapacity方法源码如下:

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

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

入参minCapacity即为calculateCapacity方法处理后的数组实际的新长度,ensureExplicitCapacity方法先进行数组实际的新长度是否比当前存储数据的数组(elementData)长度大的判断,即判断当前ArrayList的长度是否够用,是否需要扩容。

if (minCapacity - elementData.length > 0)

如果需要扩容,则调用grow(minCapacity)方法进行扩容

/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        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);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow 溢出
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。