ensurecapacity() 的核心作用是提前预留底层数组空间以避免频繁扩容;它不改变 size,只增大 elementdata.length;预估容量后调用可跳过多次 1.5 倍扩容,显著提升大批量 add 性能。

ensureCapacity() 的核心作用是提前预留底层数组空间,避免在大批量 add() 过程中反复触发 grow() —— 即复制旧数组、分配新数组、搬数据这一整套开销。它不改变 size,只影响内部 elementData 数组的 length。
明确预估容量,调用 ensureCapacity() 一次到位
如果你已知将写入约 100 万条记录,就应在循环 add 前调用:
list.ensureCapacity(1_000_000);
ArrayList 默认初始容量是 10,扩容策略是 oldCapacity + (oldCapacity >> 1)(即 1.5 倍),从 10 → 15 → 22 → 33 → …… 到突破 100 万需约 48 次扩容。而一次 ensureCapacity() 可直接跳过全部中间步骤。
注意:ensureCapacity() 不等于构造时指定容量
两者效果一致,但时机不同:
- new ArrayList(1_000_000):初始化时就分配好数组,最干净
- list.ensureCapacity(1_000_000):适用于已有 list 实例、无法重构对象的场景(如被注入的共享 list)
慎用 trimToSize(),别和 ensureCapacity() 对着干
ensureCapacity() 向上扩,trimToSize() 向下缩——它会把 elementData 缩到当前 size 大小。
如果先 ensureCapacity(1_000_000),再 add 10 万条后调 trimToSize(),底层数组会缩回 10 万长度;后续继续 add 就又触发扩容抖动。
所以:确保写入完全结束、且确认不再追加时,才考虑 trimToSize() 节省内存;高频写入期不要混用。
真实吞吐提升取决于写入模式
单线程顺序 add 百万数据时,预分配可减少 95%+ 的扩容次数,实测耗时通常下降 20%~40%;
但若写入夹杂随机 get()、remove() 或并发修改,性能瓶颈可能转移到其他环节,ensureCapacity() 收益会减弱。
它解决的是“纯写入路径上的数组复制抖动”,不是万能加速器。










