最直接有效的办法是预设容量,避免扩容过程中的数组拷贝和内存分配开销;可构造时指定初始容量或运行时调用ensurecapacity,以减少多次o(n)拷贝。

最直接有效的办法是预设容量,避免扩容过程中的数组拷贝和内存分配开销。
预估大小,初始化时指定容量
如果知道大概要存多少元素,创建 ArrayList 时就传入初始容量:
- new ArrayList(100000) 比 new ArrayList() 快 2–3 倍(实测添加 10 万条数据)
- 默认初始容量是 10,插入第 11 个元素就会触发第一次扩容,之后按 1.5 倍增长:10 → 15 → 22 → 33 → 49 → 73 → … 直到够用,中间多次复制旧数组
- JDK 7+ 启用了延迟初始化,但首次 add() 仍要分配数组;显式指定容量可跳过这一步
批量添加前调用 ensureCapacity
适用于运行时才确定规模、无法在构造时传参的场景:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 先调用 list.ensureCapacity(expectedSize),确保底层数组至少有足够空间
- 该方法只在当前容量不足时才扩容,不会缩容,也无副作用
- 比循环中反复 add() 再被动扩容更可控,能将多次 O(n) 拷贝压缩为一次
理解扩容代价,避开高频小步扩容
每次 grow() 都会调用 Arrays.copyOf(),本质是 System.arraycopy,开销来自:
- 分配新内存块(可能触发 GC)
- 逐字节拷贝所有已有元素(时间复杂度 O(n))
- 旧数组等待回收,增加内存压力
- 1.5 倍是平衡点:比 2 倍省空间,比 1.1 倍少拷贝次数
替代方案需看使用模式
不是所有场景都适合死磕 ArrayList:
- 纯尾部追加 + 已知总量 → 优先预设容量,不换结构
- 频繁中间插入/删除 → LinkedList 更合适(无扩容,但随机访问慢)
- 只读或极少修改 → 构建完可用 Collections.unmodifiableList 减少意外扩容
- 极端性能敏感且类型固定 → 考虑原生数组或专用集合(如 Eclipse Collections)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










