ArrayList扩容采用位运算newCapacity = oldCapacity + (oldCapacity >> 1)实现约1.5倍增长,因右移一位等价于整除2,比乘法更高效;该策略兼顾扩容频次与内存利用率,且避免浮点运算与溢出风险。

ArrayList 的 1.5 倍扩容,并不是直接写死的 oldCapacity * 1.5,而是通过位运算高效实现等价效果:newCapacity = oldCapacity + (oldCapacity >> 1)。
为什么用位运算代替乘法?
Java 中整数右移一位(>>)等价于除以 2 并向下取整(对非负数而言)。所以:
-
oldCapacity >> 1相当于oldCapacity / 2(整数除法) -
oldCapacity + (oldCapacity >> 1)就是oldCapacity * 1.5向下取整 - 比如原容量 10 →
10 + (10 >> 1) = 10 + 5 = 15;原容量 7 →7 + 3 = 10
扩容逻辑在源码中的位置
核心逻辑位于 grow() 方法(JDK 8+):
- 首次扩容时,若当前为默认空数组(
elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA),初始容量设为Math.max(10, minCapacity) - 后续扩容调用
newCapacity = oldCapacity + (oldCapacity >> 1) - 若计算后仍小于所需最小容量(
minCapacity),则直接使用minCapacity - 还会检查是否溢出(超过
MAX_ARRAY_SIZE),超限会调用hugeCapacity()处理
1.5 倍的设计考量
这个系数是空间与时间的平衡选择:
- 太小(如 1.1 倍)→ 频繁扩容,复制开销大
- 太大(如 2 倍)→ 内存浪费明显,尤其在中等规模数据时
- 1.5 倍在实践中兼顾了扩容次数(约 log₁.₅ N)和内存利用率,且位运算快、无浮点、无溢出风险
注意:不是严格数学意义上的 1.5 倍
由于是整数运算,实际增长是向下取整的近似:
- 容量为奇数时,会“少扩一点”:如 9 → 9 + 4 = 13(而非 13.5)
- 连续扩容序列示例(从 1 开始 add 满):1 → 2 → 3 → 4 → 6 → 9 → 13 → 19 → 28 → …
- 该序列符合递推式
cₙ = cₙ₋₁ + (cₙ₋₁ >> 1),渐进接近 1.5 倍增长趋势

















