数组的 clone() 方法看起来是个"一键复制",但它到底复制到多深,一维数组、对象数组、二维数组三种场景给出的答案真实完全不同。这篇一次性验证清楚。
上一篇:this 逃逸真实验证
最简单的场景:int[] 调用 clone(),验证修改副本是否会影响原数组。
ArrayCloneDemo.java int[] original = {1, 2, 3}; int[] cloned = original.clone(); cloned[0] = 999;
int[] clone: original == cloned: false 修改 cloned[0]=999 后,original[0] 真实保持: 1
真实结果证明基本类型数组的 clone() 是完整的值拷贝——cloned 是一个和 original 完全独立的新数组对象,元素值被真实逐个复制过去,修改一个真实不会影响另一个。
把元素类型换成自定义对象 Point,验证 clone() 是否也把每个元素对象本身复制了一份。
ArrayCloneDemo.java Point[] points = {new Point(1), new Point(2)}; Point[] pointsClone = points.clone(); pointsClone[0].x = 999;
points[0] == pointsClone[0] (元素引用): true 修改 pointsClone[0].x=999 后,points[0].x 真实变成: 999(对象数组clone只拷贝引用,元素本身共享)
二维数组的本质是"数组的数组",元素类型是 int[],这是一个引用类型——套用上面的规则,内层数组应该也是共享的。
ArrayCloneDemo.java int[][] matrix = {{1, 2}, {3, 4}}; int[][] matrixClone = matrix.clone(); matrixClone[0][0] = 999;
matrix == matrixClone: false matrix[0] == matrixClone[0] (内层数组引用): true 修改 matrixClone[0][0]=999 后,matrix[0][0] 真实变成: 999(二维数组clone只深拷贝外层,内层数组仍共享)
真实结果印证了预期:外层数组容器(int[][] 本身)被真实复制成了独立对象,但它存的每个元素——也就是内层的 int[]——只是引用被复制,指向的还是同一份内层数组。修改 matrixClone[0][0] 真实会影响到 matrix[0][0],因为 matrix[0] 和 matrixClone[0] 从头到尾都是同一个内层数组对象。这也是为什么"clone() 是浅拷贝"这句话对多维数组格外重要——很多人直觉上以为 clone() 对"数组"这种结构应该是全深拷贝,真实并非如此。
既然自动的 clone() 只深拷贝一层,想要二维数组完全独立,就要对每一行再手动调用一次 clone()。
ArrayCloneDemo.java int[][] deepClone = new int[matrix2.length][]; for (int i = 0; i < matrix2.length; i++) deepClone[i] = matrix2[i].clone();
手动逐行clone后,修改deepClone[0][0]=999,matrix2[0][0] 真实保持: 1 Arrays.copyOf 和 clone() 对基本类型数组效果真实一致: true
真实验证了这种手动逐行 clone() 的写法能达到真正的完全独立:这次修改 deepClone[0][0] 之后,matrix2[0][0] 真实保持不变。附带验证了 Arrays.copyOf() 对一维基本类型数组的效果和 clone() 真实等价,两者都是值拷贝,可以互换使用。
每一步的内容都是真实运行这段代码之后的状态。