arraylist(int initialcapacity) 构造函数省去的是扩容时的数组复制和对象迁移开销;当能预估元素数量且非极小或不可知(如查库5000行、json含200对象、目录3000文件)时应使用,设为精确值或上浮10%~20%,避免浪费内存或频繁扩容。

ArrayList(int initialCapacity) 构造函数到底省了什么
它省的是数组复制和对象迁移的开销。每次 add() 触发扩容时,ArrayList 会新建一个更大的数组(通常是原容量 1.5 倍),再把老元素逐个 System.arraycopy() 过去——这在大量添加场景下非常耗时。
什么时候该用容量构造函数
当你**能预估元素数量**,且这个数量不是极小(比如 ≤ 10)或完全不可知的时候。典型场景包括:
- 从数据库查出
List<user> users = jdbcTemplate.query(...)</user>前,已知 SQL 返回约 5000 行 - 解析 JSON 数组,知道字段
"items"包含 200 个对象 - 批量处理文件列表,
Files.list(path)后要转成ArrayList,目录里大概有 3000 个文件
如果预估偏差很大(比如预设 10000,实际只加 12 个),会浪费内存;如果完全无法预估(如用户实时输入拼接),硬设反而增加维护负担。
initialCapacity 设多少才不白设
设得太小仍会扩容,设得太大浪费堆空间。关键看后续 add() 次数:
- 若确定只 add N 次,直接传
N最稳妥(例如new ArrayList(1000)) - 若 N 是估算值,建议上浮 10%~20%,比如预估 800 就设 960;避免刚过临界点就触发第一次扩容
- 注意:传 0 是合法的(
new ArrayList(0)),但首次add()仍会分配默认 10 容量,不是“零开销” - 传负数会直接抛
IllegalArgumentException,错误信息是"Illegal Capacity: -5"
扩容策略和手动 ensureCapacity 的取舍
ArrayList 默认扩容策略(1.5 倍)对通用场景做了平衡,但如果你的写入模式很固定,可以更精细控制:
- 已知最终大小,用构造函数一次性配足,比反复
ensureCapacity()更干净 - 如果元素是分批加入(比如先加 300,停顿后加剩余 700),且你知道每批上限,可以分阶段调用
ensureCapacity(300)和ensureCapacity(1000) - 但别在循环里每轮都调
ensureCapacity()——它只是检查并扩容,不保证“刚好够”,频繁调用没收益 - 记住:
size()返回当前元素数,capacity()没有公开 API,只能靠反射或调试器看,别依赖它做逻辑判断
真正影响性能的是复制动作本身,不是容量数字。预分配的核心价值,是在数据写入前就把那块连续内存准备好,让 add() 变成纯指针赋值操作。










