预设初始容量可避免arraylist频繁扩容导致的多次数组复制开销;jdk 8+默认延迟初始化为10,插入超量元素将触发约13次扩容;推荐构造时直接指定容量如new arraylist(5000),设值应略大于预估最大size,盲目设过大反而浪费内存;该优化仅对add()有效,不影响get()、set()等操作。

频繁扩容本质是数组复制开销反复发生,而预设初始容量能直接跳过中间多次扩容过程。关键不在于“能不能避免”,而在于“什么时候设、设多少、怎么设更稳妥”。
为什么默认容量 10 容易出问题
ArrayList 无参构造时,JDK 8+ 采用延迟初始化:首次 add 才分配长度为 10 的数组。一旦插入第 11 个元素,就触发第一次扩容(10 → 15);继续添加会依次变成 22 → 33 → 49 → 73……每一步都要拷贝全部已有元素。插入 10 万个元素,实际会扩容约 13 次,产生 13 轮 O(n) 级别的数组复制。
预设容量的两种等效方式
效果完全一致,推荐优先用构造函数,语义更清晰:
-
推荐写法:直接在创建时指定,如
new ArrayList(5000)—— 构造器内部已调用ensureCapacity,一行代码搞定 -
等效写法:先无参构造,再立即调
list.ensureCapacity(5000)—— 仅在无法修改构造位置时使用(如依赖注入场景)
设多大才合适
不是越大越好,核心原则是“略大于预估最大 size”:
- 知道确切数量(如从 DB 查出 6821 条记录),设
6821或向上取整到 7000 即可 - 有波动范围(如通常 8000~12000),按上限设 12000,避免扩容;若内存敏感,可设 10000,留一点余量
- 完全不确定时,别硬猜,用默认行为更安全 —— 盲目设 1000000 只存 10 个元素,纯属浪费堆内存
它只优化 add,不影响其他操作
ensureCapacity 和构造时设容量,只减少 add() 过程中的扩容复制开销:
- 对
get()、set()、remove()等随机访问或尾部操作,没有加速作用 - 如果业务中大量在中间位置
add(index, e)或remove(index),性能瓶颈其实在元素搬移,此时预设容量意义不大,应考虑换数据结构
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











