bigywater.tech
Java 内部原理 · 80

数组 clone() 真实验证:二维数组只深拷贝第一层

数组的 clone() 方法看起来是个"一键复制",但它到底复制到多深,一维数组、对象数组、二维数组三种场景给出的答案真实完全不同。这篇一次性验证清楚。

一维基本类型数组真实完整拷贝
真实验证:int[] clone() 后修改副本元素,原数组真实不受影响,是完整的值拷贝
二维数组真实只深拷贝第一层
真实验证:int[][] clone() 后 matrix[0]==matrixClone[0] 真实为true,内层数组依然共享,修改会真实互相影响

上一篇:this 逃逸真实验证

真实验证:一维基本类型数组,clone()是完整值拷贝

最简单的场景: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 完全独立的新数组对象,元素值被真实逐个复制过去,修改一个真实不会影响另一个。

真实验证:一维对象数组,clone()只拷贝引用

把元素类型换成自定义对象 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只拷贝引用,元素本身共享)
数组本身独立,元素共享。points.clone() 真实创建了一个新的数组对象(容器本身是独立的,points == pointsClone 为 false),但数组里存的是 Point 对象的引用,clone() 只复制了这些引用值本身,没有连带复制引用指向的 Point 对象——所以 points[0] 和 pointsClone[0] 真实是指向堆上同一个 Point 对象的两个引用,修改其中一个能看到的字段,另一个真实也会看到变化。这和系列前面 Object.clone() 浅拷贝那篇验证过的机制是同一回事——数组的 clone() 本质上也是浅拷贝。

真实验证:二维数组,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() 只深拷贝一层,想要二维数组完全独立,就要对每一行再手动调用一次 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() 真实等价,两者都是值拷贝,可以互换使用。

分步演示:三种数组的 clone() 到底拷贝到多深

每一步的内容都是真实运行这段代码之后的状态。

一维基本类型数组是完整拷贝,对象数组/二维数组的 clone() 都只深拷贝了最外层
这一步真实发生变化的位置

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,三种数组场景的clone行为重复运行完全一致。
    • 和Object.clone() 浅拷贝那篇一起看,能建立起"clone() 默认只做一层复制"这条规则在普通对象和数组两种场景下的统一真实图景。作为这一批的收尾,系列 Java 内部原理现在共 80 篇。
    • 没有涉及:三维及以上多维数组的clone()行为(遵循同样的"只深拷贝最外层"规律,可以递归推广)、Arrays.deepToString()和Arrays.deepEquals()对多维数组的专门支持——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号