java arraylist扩容是按需增长、带边界控制的智能策略,触发条件为add时size+1超过当前数组长度,新容量通常为1.5倍旧容量(首次为10),扩容通过数组复制实现,预设合理初始容量可显著减少扩容次数。

Java ArrayList 的扩容不是“每次加10”或“固定翻倍”,而是按需增长、带边界控制的智能策略。理解它,能避开性能坑,写出更稳的代码。
扩容触发条件很明确
每次调用 add() 方法时,ArrayList 都会检查:
size + 1 > elementData.length
即:当前元素个数再加1,是否超过底层数组能容纳的最大数量。
只要不满足,就直接插入;一旦超限,立刻走扩容流程。注意,不是等数组填满才扩,而是“即将放不下”就扩。
新容量怎么算:1.5 倍为主,但有兜底
扩容核心逻辑在 grow() 方法里,计算分三步:
- 取旧容量 oldCapacity = elementData.length
- 尝试扩容为 oldCapacity + (oldCapacity >> 1)(右移1位 = 除以2,等价于 ×1.5)
- 如果这个值仍小于本次操作所需的最小容量(比如一次 addAll 传入大量元素),则直接设为该最小容量
例如:
• 初始空构造,首次 add → 容量从 0 → 10(特殊处理,非1.5倍)
• 容量10时第11次 add → 10 + 5 = 15
• 容量15时第16次 add → 15 + 7 = 22(15>>1 = 7,向下取整)
• 容量22时第23次 add → 22 + 11 = 33
扩容过程本质是数组复制
扩容不是原地放大,而是三步原子操作:
- 分配一个新数组,长度为刚算出的新容量
- 调用 Arrays.copyOf(elementData, newCapacity) —— 底层实际调用 native 的 System.arraycopy,高效拷贝
- 将 elementData 引用指向新数组,旧数组等待 GC 回收
这意味着:扩容时间复杂度是 O(n),且会短暂产生两倍内存占用(旧+新数组共存),对 GC 有一定压力。
性能优化关键在预估容量
频繁扩容会拖慢吞吐、引发 GC 晃动。最简单有效的优化方式,就是初始化时给足空间:
- 已知要存 1000 条数据?用 new ArrayList(1000),避免中途多次扩容
- 从集合构造?优先用 new ArrayList(sourceCollection),它会按 source.size() 初始化容量
- 不确定规模但偏大?宁可略高估(如预设 2048),也比反复扩容划算
实测表明:预设合理初始容量,可减少 90% 以上扩容次数,尤其在批量写入场景下效果显著。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











