collections.ncopies(n, obj) 返回共享引用的不可变视图,内存恒定且只存一份obj和n,适合只读占位;若需可变或独立实例,应转arraylist或用stream.generate。

使用 Collections.nCopies 可以快速创建一个“逻辑上”包含 N 个相同元素的不可变列表,它不真正分配 N 个对象实例,而是通过代理机制实现视图式复用——这是构建轻量级虚拟列表的核心技巧。
理解 nCopies 的本质:共享引用 + 不可变视图
Collections.nCopies(n, obj) 返回的是 java.util.Collections$CopiesList 类型实例,它内部只保存一份 obj 引用和数量 n,所有 get(i) 调用都返回同一个对象。这意味着:
- 内存占用恒定,与
n无关(仅约 24 字节对象头 + 两个字段) - 列表不可修改:调用
add、set、clear等会直接抛UnsupportedOperationException - 适合做只读场景下的占位、默认值填充或 UI 列表预占位
典型实战场景:避免重复构造对象的列表占位
比如在 RecyclerView 或 TableModel 中需要显示 100 行「暂无数据」占位项,但不想创建 100 个相同空对象:
List<string> placeholders = Collections.nCopies(100, "—");</string>
此时 placeholders.get(0) == placeholders.get(99) 为 true,且不会触发任何字符串重复分配。
注意:若传入的是可变对象(如 new ArrayList()),所有索引都指向同一实例,修改任一位置会影响全部——这不是 bug,而是设计使然,需谨慎使用。
安全扩展:转为可变副本(按需物理分配)
当后续需要独立修改某一项时,不能直接修改 nCopies 列表,而应显式复制出真实副本:
- 转为
ArrayList并深拷贝(适用于不可变对象):new ArrayList(Collections.nCopies(100, "default")) - 对可变对象,需配合工厂函数生成独立实例:
Stream.generate(() -> new MutableItem()).limit(100).collect(Collectors.toList()) - 若只需局部更新,可用
subList+new ArrayList提取片段再操作
避坑提醒:常见误用与替代建议
以下情况不宜直接使用 nCopies:
- 需要支持
set(i, x)动态更新某一项 → 改用Arrays.fill配合数组,或自定义懒加载列表 - 元素是可变对象且预期各自独立 → 必须用循环或 Stream 生成新实例
- 需序列化传输 →
CopiesList不实现Serializable(JDK 8+ 已修复,但低版本仍需注意) - 与某些泛型工具类(如 Lombok 的
@Singular)冲突 → 显式构造ArrayList更稳妥










