Java中ArrayList扩容机制与底层源码剖析

扩容机制

结论

transient Object[] elementData

  1. ArrayList中维护了一个Object类型的数组, elementData
  2. 当创建ArrayList对象时, 如果使用的是无参构造器, 则初始elementData容量为0, 第一次添加
    扩容elementData为10, 如需要再次扩容, 则扩容elementData为1.5倍
  3. 如果使用的是指定大小的构造器, 则下次扩容会扩容1.5倍

源码解读

利用断点调试进入底层源码查看如何执行和扩容

无参构造器

代码如下

public class Main {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();

        for (int i = 1; i <= 10; i++) {
            arrayList.add(i);
        }
        for (int i = 11; i <= 15; i++) {
            arrayList.add(i);
        }

        arrayList.add(100);
        arrayList.add(null);

    }
}

初始化

可以发现一开始elementData 确实初始化成为一个空数组

扩容

进入for 循环中, 因为是对象数组, add() 方法也是添加的对象, 所以要先进行自动装箱

然后将对象加入

解读

  1. modCount用来记录集合被修改的次数
  2. add() 中会传入三个参数, 添加的对象, 被添加的数组, 以及大小
  3. 如果大小达到上限, 那么会执行grow()扩容

仔细阅读之后我们可以发现, 这里进行了一步判断

  1. 如果当前elementData 为空, 那么我们会直接将其扩容为max(10, minCapacity), (那个宏的大小为10)
  2. 否则, 那么会计算几个量

minCapacity - oldCapacity 这个是最小的增量
oldCapacity >> 1 这个是原来容量的一半
oldCapacity 这个是原来的容量
然后进入ArraysSupport.newLength() 方法, 获得新的容量, 然后扩容
查看ArraysSupport.newLength() 方法

解读

  1. 这里我们发现, 如果minGrowthprefGrowth 小, 那么我们就会扩容1.5倍, 和结论吻合
  2. 但是如果扩容1.5倍解决不了问题, 就会扩容原来容量+最小增量, 就不是1.5倍了, (比如塞入一个大数组)
  3. 如果扩容之后容量超过SOFT_MAX_ARRAY_LENGTH, 那么就会进入hugeLength

可以看到这是一个上限

进入hugeLength可以发现, 这就是一个保险函数, 不让数组过大, 且会给你提醒

有参构造器

public class Main {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList(7);

    }
}

可以看到如果是指定大小就会创造一个指定大小的Object数组, 如果是负数就抛出异常, 如果是0就走无参构造那一套

posted @   Xingon2356  阅读(12)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示