合理预估并设置arraylist初始容量可显著减少扩容次数与数组复制开销;扩容需新建数组、复制元素、等待gc,代价高昂;应据场景选择:已知数量直接指定,有上界按上限设,批量构建先统计再初始化,偏小可沿用默认10。

ArrayList 在创建时指定合适的初始容量,能显著减少扩容带来的数组复制开销。关键不是“避免扩容”,而是“让扩容次数尽可能少”——只要预估元素数量较准,通常 1~2 次扩容就足够。
为什么扩容代价高?
每次扩容(默认增长 50%)都需要:
- 创建新数组(大小为 oldCapacity + oldCapacity >> 1)
- 调用 System.arraycopy 把旧元素逐个复制过去
- 原数组等待 GC —— 对大列表来说,这会明显拖慢 add() 性能,尤其在循环批量添加时
怎么估算初始容量才靠谱?
别猜,看实际使用场景:
- 已知确切数量:比如从数据库查出 127 条记录,直接写 new ArrayList(127)
- 有合理上界:如 HTTP 请求参数最多支持 20 个 header,用 new ArrayList(20)
- 批量构建且可预估:读取文件行数前先 Files.lines(path).count(),再初始化;或用 Scanner 先 scan 一遍获取大致规模
- 不确定但偏小:默认容量是 10,如果平均只存 3~5 个对象,不设也无妨;若平均 30+,建议至少设 32 或 48(避开多次 10→15→22→33 的跳变)
扩容规律和推荐值
默认扩容公式:newCapacity = oldCapacity + (oldCapacity >> 1)(即 ×1.5)
所以常见容量序列是:10 → 15 → 22 → 33 → 49 → 73 → 109 …
如果你知道最终要装 n 个元素,反推最小初始容量:
- n ≤ 10 → 用默认即可
- 10
- 15
- 更简单方法:向上取整到最接近的“10, 16, 32, 64, 128…”等 2 的幂附近值(虽非严格匹配扩容步长,但便于心算且足够安全)
构造后还能优化吗?
可以,但仅限“一次性填充后不再增删”的场景:
- 调用 trimToSize():把内部数组缩到当前 size() 大小,释放冗余空间
- 注意:之后再 add() 会立刻触发扩容,所以只在确定“填充完成且只读”时用
- 例如:配置加载器解析完所有配置项,生成不可变列表,此时 trim 很划算
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











