collections.ncopies 返回只读视图,所有元素共享同一引用,适合不可变类型初始化;对可变对象会引发副作用,修改任一元素影响全部,且调用 add/set/remove 等方法抛 unsupportedoperationexception。

用 Collections.nCopies 生成重复元素列表,本质是“只读视图”
它不真创建 N 个新对象,而是返回一个轻量级的、固定大小的不可变列表——背后共享同一份引用。这意味着:所有元素都指向同一个对象实例,改其中一个,全都会变(如果该对象可变)。
- 适合用来初始化
Arrays.asList()或填充默认值(比如Collections.nCopies(5, "default")) - 不能用于含可变对象的场景:比如
Collections.nCopies(3, new ArrayList()),三个位置其实是同一个ArrayList实例 - 调用
set()、add()、remove()会直接抛UnsupportedOperationException
想真正复制对象?别依赖 nCopies,得手动构造
很多人误以为 Collections.nCopies(n, new Date()) 能生成 n 个不同时间点的 Date 实例——实际只会创建一次 Date(),然后复用引用。结果所有元素时间戳完全一样。
- 正确做法是用循环或 Stream:
Stream.generate(Date::new).limit(5).collect(Collectors.toList()) - 如果元素类型支持克隆,也可结合
stream().map(Date::clone)(注意判空和异常) - 对简单不可变类型(
String、Integer等),nCopies安全且高效,不用额外开销
nCopies 的性能和内存表现很“省”,但别把它当普通 ArrayList 用
它底层是 CopiesList,没有底层数组拷贝,get(i) 是 O(1) 但纯计算(返回同一个引用),size() 返回传入的 n,contains() 是 O(n) 遍历比较引用。
- 内存占用几乎恒定,和
n大小无关;而new ArrayList(Collections.nCopies(...))会立刻展开成真实数组,失去优势 - 序列化时,它会把整个逻辑结构写进去,反序列化后仍是只读视图,不是深拷贝
- 和
Arrays.asList()类似,它只是 List 接口的“薄包装”,别试图转型成ArrayList或调用其特有方法
常见报错:UnsupportedOperationException 出现在哪几个操作上
只要试图修改这个列表,JVM 就会立刻拒绝。最典型的是在你没注意它是只读的情况下,直接传给需要可变列表的方法。
立即学习“Java免费学习笔记(深入)”;
-
list.add("x")→ 报UnsupportedOperationException -
list.set(0, "y")→ 同样报错(哪怕原值就是 "y") -
list.remove(0)、list.clear()、list.retainAll(...)全部不行 - 安全操作只有:
get()、size()、contains()、indexOf()、iterator()(但迭代器也不支持remove())
最容易被忽略的一点:它和 Arrays.asList() 一样,表面看是 List,实则行为边界极窄——不是所有 List 接口方法都真正可用。用之前先想清楚,你要的是“数据容器”还是“占位符”。










