Collections.nCopies() 返回只读视图,底层共享引用,适用于不可变类型或只读场景;若需独立可变对象,应使用 Stream.generate() 或循环构造。
用
创建不可变重复列表时,别直接当普通
用
它返回的是只读视图,底层共享同一引用 —— 所以如果你传入的是可变对象(比如
),所有位置都指向同一个实例。修改其中任意一个,整个列表“全跟着变”。
正确场景:初始化
、
等不可变类型,或仅作只读用途
错误写法:
→ 三个元素其实是同一个
实例
想每个都是独立对象?得配合
或循环构造,不能只靠
的参数边界和性能表现
第一个参数是数量,必须 ≥ 0;负数会抛
;第二个参数是填入的元素,可以为
(生成的列表里对应位置就是
)。
时间复杂度 O(1),不真正创建
个对象,只是逻辑上“看起来有 n 份”
内存占用极小,适合做大容量只读占位,比如初始化 10 万长度的默认值列表
但调用
是 O(1),而
会直接抛
替代方案:需要可变且独立副本时怎么写
如果目标是“n 个互不影响的可变对象”,
不适用,必须显式构造。
Java 8+ 推荐:
传统写法:
注意:不要写成
—— 这仍是单实例复用,不是复制
常见报错:为什么
或
会失败
因为
返回的是
,内部没有实现结构性修改方法。
触发异常:
,错误信息类似
哪怕你把它赋给
接口变量,也不改变其不可变本质
如果后续要增删,必须转成可变实现:
—— 但注意这会真实复制引用(不是深拷贝)
实际用的时候,先问自己一句:这个列表之后会不会被修改?每个元素是否必须彼此隔离?答案决定你是用
、
,还是老老实实写循环。
Collections.nCopies()Listnew ArrayList()StringIntegerList> list = Collections.nCopies(3, new ArrayList()) ArrayListStream.generate()nCopiesCollections.nCopies()IllegalArgumentExceptionnullnullnget(i)set(i, x)UnsupportedOperationExceptionnCopiesList list = Stream.generate(MyObj::new).limit(n).collect(Collectors.toList()) List list = new ArrayList(n); for (int i = 0; i Collections.nCopies(n, new MyObj())add()remove()Collections.nCopies()java.util.Collections$CopiesListUnsupportedOperationException"add" not supportedListnew ArrayList(Collections.nCopies(n, "x"))nCopiesStream.generate