ArrayList的1.5倍扩容通过位运算oldCapacity + (oldCapacity >> 1)实现,非浮点计算;首次扩容固定为10,后续按该公式增长并动态适配最小容量需求,真正开销在于O(n)的数组拷贝。

ArrayList 的 1.5 倍扩容不是靠 * 1.5 这种浮点运算,而是用整数位运算高效实现的:每次扩容时执行 oldCapacity + (oldCapacity >> 1)。右移一位(>>)等价于整数除以 2(向下取整),所以结果天然接近原容量的 1.5 倍,且全程无浮点开销、无舍入误差。
扩容计算不是固定倍率,而是“尝试按 1.5 倍扩”
真正的新容量由三步决定:
- 先算出基础值:
newCapacity = oldCapacity + (oldCapacity >> 1) - 再和“实际最少需要的容量”(比如
size + 1或size + c.size())比较;如果基础值不够,就直接取所需最小值 - 最后检查是否超过
MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8),超了就进溢出处理逻辑
例如:当前容量 15,要 add 第 16 个元素 → 需要至少 16 个空间 → 计算 15 + (15 >> 1) = 15 + 7 = 22 → 22 ≥ 16,所以新容量为 22;但如果是一次 addAll(100),而当前容量只有 50,则 50 + 25 = 75 仍小于 100,最终新容量直接设为 100。
首次扩容是特例,不走 1.5 倍公式
用 new ArrayList() 创建时,底层数组是空的(长度为 0)。第一次调用 add() 会跳过位运算逻辑,直接进入 calculateCapacity(),返回 Math.max(10, size + 1) → 默认变成 10。这说明 10 是约定的初始门槛,不是 1.5 倍推导出来的。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
而 new ArrayList(1) 或 new ArrayList(0) 行为一致:都分配指定长度的数组,后续扩容才启用 1.5 倍规则。
扩容真正耗时的操作不在算容量,而在复制数据
确定 newCapacity 是瞬间完成的整数运算;真实开销来自:
- 调用
Arrays.copyOf(elementData, newCapacity) - 底层依赖
System.arraycopy,把原数组中全部size个有效元素逐字节拷贝到新数组 - 时间复杂度为 O(n),n 是当前
size,不是容量 - 同时产生一个临时大数组,可能触发 Minor GC,尤其当元素含
byte[]等大字段时更明显
为什么选 1.5 而不是 2 倍或 1.25 倍?
这是空间与时间的工程权衡:
- 比 2 倍省内存:从 10→20 多预留 10 个空位,10→15 只多 5 个,长期运行下节省约 25% 预留空间
- 比 1.25 倍少扩容:10→12→15→18…轮次更多,复制总次数上升;1.5 倍在常见写入模式下综合性能最优
- 位运算友好:
>>比/ 2更快、更底层,适合高频调用场景

















