可以直接用 new ArrayList<>(Collections.nCopies(n, value)) 初始化可变列表,它会复制元素生成标准可修改 ArrayList;但若 value 是可变对象,则所有元素共享同一引用,需用 Stream.generate 或循环创建独立实例。

直接用 Collections.nCopies 创建的是不可变列表,不能直接用于初始化可变的 ArrayList;必须显式拷贝一份,否则调用 add、set 等方法会抛出 UnsupportedOperationException。
为什么不能直接 new ArrayList(Collections.nCopies(...))?
Collections.nCopies(n, value) 返回的是一个轻量级的不可变 List 实现(内部是 CopiesList),它不支持修改操作。虽然 ArrayList 构造函数能接受任意 Collection,但新创建的 ArrayList 只是把不可变视图里的元素“复制”进来——这一步才是关键:只要构造完成,得到的就是标准的、可修改的 ArrayList。
所以实际上:可以且常用 new ArrayList(Collections.nCopies(n, value)),它是安全、简洁、高效的初始化方式。
正确写法:一行搞定可变列表初始化
这是最常用也最推荐的方式:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 创建含
n个相同元素的可变ArrayList - 底层真正复制了值,后续可自由
add、set、remove - 适用于基本类型包装类、字符串、自定义对象(注意:所有元素引用相同对象!)
示例:
ArrayList<String> list = new ArrayList<>(Collections.nCopies(5, "default"));
list.set(2, "changed"); // ✅ 合法
list.add("new"); // ✅ 合法
注意引用类型陷阱:所有元素指向同一个对象
如果填充值是可变对象(如 new ArrayList<>() 或自定义类实例),nCopies 会重复添加**同一引用**,导致修改任一元素影响全部:
// ❌ 危险!5 个元素都指向同一个 ArrayList 实例
ArrayList<ArrayList<Integer>> lists = new ArrayList<>(
Collections.nCopies(5, new ArrayList<>())
);
lists.get(0).add(1);
System.out.println(lists.get(1)); // 输出 [1] —— 被意外改了!
解决办法:用循环或流生成独立对象:
- 传统 for 循环:手动 new 每个实例
- Java 8+:用
Stream.generate(() -> new ArrayList<>()).limit(5).collect(Collectors.toCollection(ArrayList::new))
替代方案对比(何时不用 nCopies)
当需要默认值是不同对象、或需预分配容量但暂不填值时,考虑其他方式:
- 只预分配容量(全为
null):new ArrayList<>(n) - 填
null或基础默认值:Arrays.asList(new Integer[n])→ 再转ArrayList(注意数组类型限制) - 复杂初始化逻辑:优先用 for 循环,语义清晰不易出错
而 Collections.nCopies 最适合:值固定、不可变、或可变但你明确知道共享引用无害的场景(如 "abc"、Integer.valueOf(42))。

















