arraylist扩容采用1.5倍机制,通过位运算newcapacity = oldcapacity + (oldcapacity >> 1)实现,兼顾内存利用率与扩容频次,在空间节省与复制开销间取得平衡。

ArrayList 底层用数组实现,扩容时不是简单翻倍,而是按 oldCapacity + (oldCapacity >> 1) 计算新容量——也就是 1.5 倍。这个设计在空间利用率和扩容频次之间做了折中,既避免频繁扩容影响性能,又不至于过度浪费内存。
扩容公式:1.5 倍的精确计算逻辑
当添加元素导致数组满时,ArrayList 调用 grow() 方法扩容。核心逻辑是:
- 新容量 = 旧容量 + 旧容量右移一位(即除以 2),等价于
oldCapacity * 1.5 - 若计算结果仍小于所需最小容量(比如 add 时发现不够),则直接设为最小容量
- 若新容量超过
MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8),会触发溢出处理,尝试分配最大可能值
为什么选 1.5 倍而不是 2 倍?
2 倍扩容虽简单,但容易造成内存浪费,尤其在多次扩容后;1.5 倍在实践中更平衡:
- 比 2 倍节省约 25% 的预留空间,对长期运行、内存敏感的场景更友好
- 相比 1.25 倍或 1.33 倍,1.5 倍显著降低扩容次数,减少数组复制开销
- 位运算
>> 1效率高,不依赖浮点运算,适合高频调用
高频随机访问为何快?靠的是数组连续内存布局
ArrayList 支持 O(1) 时间复杂度的 get(index),关键在于:
- 底层 Object[] 数组在 JVM 中分配连续内存块,CPU 缓存预取友好
- 访问时只需计算偏移量:
baseAddress + index * elementSize,无须遍历或哈希查找 - 相比 LinkedList 的链式跳转,少几十个 CPU cycle,实测在万级数据下随机读取快 5–10 倍
注意:扩容本身是代价较高的操作
虽然 1.5 倍设计优化了平均成本,但每次扩容仍需:
- 分配新数组
- 调用
System.arraycopy()复制原数据 - 旧数组等待 GC,短时内存占用翻倍
若能预估大小(如已知要存 1000 个元素),建议构造时指定初始容量:new ArrayList(1000),可完全规避前几次扩容。











