collections.copy要求目标列表size≥源列表size,因其通过dest.set(i, src.get(i))逐索引覆写,不扩容也不添加元素;常见错误是目标为空或长度不足,正确做法是预设足够size或直接new arraylist(src)。

Java 中 Collections.copy 要求目标列表(destination)的长度必须大于等于源列表(source)的长度,否则会抛出 IndexOutOfBoundsException。这不是容量(capacity)问题,而是实际元素个数(size)问题——目标列表必须已存在至少与源列表等长的元素,才能逐个覆盖。
为什么不是“容量”而是“长度”?
Collections.copy 的实现是按索引遍历源列表,把每个元素赋值给目标列表对应索引位置:dest.set(i, src.get(i))。
它不调用 add(),也不扩容;它依赖目标列表已有足够多可写的索引位置。所以关键不是 ArrayList 内部数组的 capacity,而是 dest.size() ≥ src.size()。
常见错误写法及修复
-
错误:新建空 ArrayList 后直接 copy
List<string> dest = new ArrayList();<br> Collections.copy(dest, src); // 抛异常:size=0 </string>
-
错误:用 Arrays.asList 初始化但长度不够
List<string> dest = Arrays.asList("a", "b"); // size=2<br> Collections.copy(dest, Arrays.asList("x", "y", "z")); // size=3 → 异常</string> -
正确做法一:预设足够长度的可变列表
List<string> dest = new ArrayList(Collections.nCopies(src.size(), null));<br> Collections.copy(dest, src);</string>
-
正确做法二:用构造函数初始化(推荐)
List<string> dest = new ArrayList(src); // 直接复制,更安全简洁</string>
什么时候该用 Collections.copy?
这个方法适用场景有限,主要用在:
- 目标列表已预先分配好固定长度(比如复用缓存列表);
- 需要原地覆盖而非新建对象(避免 GC 压力);
- 源和目标类型兼容且目标支持 set 操作(如 ArrayList、Vector,但不支持 Arrays.asList 返回的不可变列表)。
替代方案更常用
日常开发中,多数情况建议避开 Collections.copy:
- new ArrayList(src) —— 最直观、安全、通用;
- src.stream().collect(Collectors.toList()) —— 支持中间操作;
- List.copyOf(src)(Java 10+)—— 创建不可变副本;
- 若需深拷贝,应手动遍历或使用序列化/工具类,因为 Collections.copy 是浅拷贝。
本质上,这个限制不是 bug,而是设计使然:它假设你明确控制目标状态,只负责“覆写”,不负责“构建”。理解这点,排查就简单了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











