arrays.fill()填可变对象会导致所有元素共享同一实例,修改一个会影响全部;应区分“填值”与“造对象”,安全做法包括显式循环、arrays.setall()或stream.generate()。

Arrays.fill() 填可变对象时,所有数组元素都指向同一个实例——改一个,全跟着变。这不是 bug,而是 Java 引用语义的自然结果。关键不是避免用 fill,而是分清“填值”和“造对象”两件事。
为什么填 new ArrayList() 会出问题
Arrays.fill(lists, new ArrayList()) 这行代码只创建了一次 ArrayList 实例,然后把这个实例的引用复制到每个数组位置。数组里存的不是 5 个列表,而是 5 个指向同一块内存的指针。
- 执行 lists[0].add("x") 后,lists[1].size() 也变成 1
- lists[0] == lists[1] 返回 true
- 调试器里展开,所有元素显示 “same as #1”
安全填充可变对象的三种可靠做法
目标是让每个数组元素持有独立对象,而不是共享引用。
-
显式循环构造:最直观、无歧义
for (int i = 0; i lists[i] = new ArrayList();
} -
Arrays.setAll():函数式写法,语义清晰
Arrays.setAll(lists, i -> new ArrayList()); -
Stream.generate()(适用于新建数组):
List>[] arr = Stream.generate(ArrayList::new)
.limit(5)
.toArray(List[]::new);
哪些情况可以放心用 fill
不是所有对象都不能填,关键是看它是否可变、是否会被后续修改。
- 字符串字面量("OK"):常量池保证安全,且 String 不可变
- 包装类字面量(0、false、null):基本类型或不可变对象,无副作用
- 不可变容器(如 Collections.unmodifiableList(...)):即使共享,也无法被修改
二维数组别走捷径
int[][] grid = new int[3][4];
不能 Arrays.fill(grid, new int[]{0,0,0,0}); —— 这会让所有行引用同一子数组。
- 正确做法:for (int[] row : grid) Arrays.fill(row, 0);
- 若需每行不同初值,可在循环中动态传参:
for (int i = 0; i
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











