Java ArrayList动态扩容机制

微信公众号同步更新

欢迎和小白一起成长,985计算机硕士,有任何学习保研等问题都可以公众号私信留言哦!

微信搜索:三喂树屋

手把手看源码

上篇实现了一个动态扩容数组,扩容原理大致相同,但比起java实现的扩容机制,还是有很大不同,
下面我们看一下java中ArrayList的扩容机制。

ArrayList:
1. 可动态修改的数组
2. 没有固定大小的限制

在这里插入图片描述
在add()函数处打个断点,开始debug起来!

然后点击:Force Step Into
在这里插入图片描述
首先进入的是自动装箱机制:
在这里插入图片描述
点击 Step into跳回到add这里
在这里插入图片描述
再次点击Force Step Into,进入add函数

在这里插入图片描述
从函数名字也能看出ensureCapacityInternal(size + 1)便是负责执行ArrayList的动态扩容的。
再次点击Force Step Into,进入ensureCapacityInternal()函数:
在这里插入图片描述
调用了 ensureExplicitCapacity()函数,ensureCapacityInternal方法调用ensureExplicitCapacity 方法实现动态扩容,在调用ensureExplicitCapacity 方法之前,java还调用了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实际存储数据元素的个数,minCapacity表示的含义就是:如果我要add(element)成功执行的话,那数组的容量应该至少为size+1,否则add()失败。
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为空,则返回传入的minCapacity和DEFAULT_CAPACITY中的最大值,其中DEFAULT_CAPACITY为elementData数组的默认长度:

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

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

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

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

入参minCapacity即为add()函数成功执行所要求的数组最小的容量,而elementData.length为数组当前数组的最大容量,如果add()函数要求的最小容量大于当前数组的最大容量,那说明需要扩容,执行grow()函数

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //扩容后的容量为1.5*oldCapacity 
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //oldCapacity如果仍然比add()要求的最小容量小,那么直接讲minCapacity 赋值给newCapacity(Integer.MAX_VALUE - 8),则执行hugeCapacity
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
         //如果新容量大于MAX_ARRAY_SIZE 
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        //讲新的数组赋值给elementData
        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;
    }

图解

这里先展示一下空参构造函数,即在new一个arraylist时,不传入长度,使用默认值,然后看一下扩容逻辑

public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
    }

由于arratylist真正存储数据的是elementData对象数组,我们只需看这个存储数组即可,初始状态和关键变量值如下:

在这里插入图片描述

然后进入calculateCapacity()函数,条件满足if语句,执行return Math.max(DEFAULT_CAPACITY, minCapacity);返回DEFAULT_CAPACITY=10

在这里插入图片描述

执行**ensureExplicitCapacity()然后执行grow()**函数

在这里插入图片描述

最后执行完add之后,状态如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三喂树屋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值