Collections.nCopies生成的是只存element引用和数量n的逻辑视图,内存恒定约24–32字节,get(i)直接返回同一引用,O(1)时间且无GC压力,适合只读场景。

Collections.nCopies 生成的“重复列表”本质上不是列表,而是一个逻辑视图——它不分配 N 个对象空间,只存一份元素引用和数量 n,所有 get(i) 都返回同一个对象。
内存只存两个字段:element + n
它返回的是 Collections$CopiesList(私有静态内部类),内部仅含三个字段:
- element:被复用的对象引用(比如一个 String 或 null)
- n:逻辑长度(如 100 万)
- hashCode:懒计算,首次调用才算,之后缓存
无论 n 是 10 还是 10⁷,内存占用都稳定在约 24 字节(对象头)+ 两个引用/整型字段,完全不随规模增长。
get(i) 不查数组,直接返引用
每次调用 list.get(i),底层不做索引查找或对象复制,而是直接返回 stored element。没有底层数组、没有循环拷贝、没有对象实例化——纯计算返回同一份引用。
立即学习“Java免费学习笔记(深入)”;
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 时间复杂度 O(1),且常数极小
- 不会触发任何 new 操作,也不增加 GC 压力
- 对 String、Integer 等不可变类型完全安全
共享引用是设计,不是缺陷
如果传入的是可变对象(如 new ArrayList()),所有位置 get 出来的都是同一个实例。这不是 bug,而是复用机制的自然结果:
List<list>> rows = Collections.nCopies(5, new ArrayList());</list>-
rows.get(0).add("x");→rows.get(4).size()也变成 1
这种行为恰恰印证了“零副本”的本质:它根本没造新对象,只是把一个句柄反复亮出来。
与真实列表的对比更显优势
手动构造等价列表需 O(n) 时间和空间:
for (int i = 0; i :分配百万级引用(约 8MB)+ 扩容开销-
Collections.nCopies(1_000_000, "x"):瞬时完成,内存≈32 字节
它省掉的不是“代码行数”,而是实实在在的堆内存和初始化时间——尤其适合占位符、默认配置、测试桩等只读高频场景。

















