java数组clone()是浅拷贝:基本类型数组因值复制而表现如深拷贝,引用类型数组(含string[]、对象数组)仅复制引用,二维数组只克隆外层;真正深拷贝需手动遍历、序列化或工具类。

Java 数组的 clone() 方法默认只做浅拷贝,对基本类型数组表现为“深效果”,但对引用类型数组(包括 String[]、自定义对象数组等)仅复制引用,不复制对象本身——这常被误认为是“深拷贝”,实际仍是浅拷贝。
数组 clone() 的真实行为:为什么说它“看似深、实为浅”
数组类型在 JVM 中被自动视为实现了 Cloneable 接口,因此无需显式声明即可调用 clone()。但它的拷贝逻辑统一为:只复制数组容器本身 + 元素值(基本类型)或引用地址(引用类型)。
- int[]、double[] 等基本类型数组:每个数值被完整复制,新旧数组完全独立——这是“值拷贝”,效果等同于深拷贝,但本质仍是浅拷贝操作(JVM 按字节块复制)。
-
String[]:数组被复制,元素仍指向原字符串对象;但由于
String不可变,修改cloned[i] = "new"实际是重新赋值引用,不会影响原数组,所以安全但非深拷贝。 -
Person[]、List[] 等可变引用类型数组:
cloned[0].setName("X")会同步改变原数组中同一对象的状态,因为两个数组的索引 0 都指向堆中同一个Person实例。
二维及多维数组的克隆陷阱
数组的 clone() 只作用于最外层,内层数组仍是共享引用。例如:
int[][] matrix = {{1,2}, {3,4}};int[][] copied = matrix.clone();
此时 copied[0] == matrix[0] 为 true —— 第一行数组未被复制,只是引用被拷贝。
- 修改
copied[0][0] = 99,原matrix[0][0]同样变为 99。 - 要真正隔离,需手动遍历每行调用
row.clone(),或使用工具类如ArrayUtils.deepClone()(Apache Commons)。
实现真正深拷贝的可行路径
Java 没有内置数组深拷贝 API,必须主动处理引用层级:
-
一维对象数组:遍历并调用每个元素的
clone()(要求该类已正确实现深克隆),或用构造器重建:new Person(p.getName(), p.getAge())。 -
嵌套数组:双重循环 + 每层
clone(),例如int[][]可写成:Arrays.stream(original).map(int[]::clone).toArray(int[][]::new)。 -
通用稳妥方案:序列化反序列化(要求所有元素实现
Serializable),或借助 JSON 库(如 Jackson)转字符串再解析——虽有性能开销,但彻底断开引用链。
别踩坑:自定义容器类不继承数组特权
如果你把数组封装进一个类(比如 class MyList { private String[] data; }),这个类本身不自动具备克隆能力。即使内部是数组,外部调用 myList.clone() 仍会抛出 CloneNotSupportedException,除非你显式实现 Cloneable 并重写 clone() 方法,且手动处理 data.clone() 和深层逻辑。
数组的“免接口克隆”是 JVM 特殊机制,仅限数组类型本身,不可传递、不可继承。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











