java中cloneable接口仅作标记,object.clone()默认执行字段级浅拷贝;深拷贝需手动递归克隆每个可变引用字段,并确保其类型也支持克隆。

Java 中通过实现 Cloneable 接口并重写 clone() 方法,**默认只能实现浅拷贝**;要实现深拷贝,必须在重写的 clone() 方法中**手动对所有可变的引用类型成员进行递归克隆**。
为什么 `Cloneable` 本身不提供深拷贝?
Cloneable 是一个空标记接口(marker interface),它不定义任何方法。真正起作用的是 Object.clone() —— 这个受保护方法由 JVM 特殊处理,执行的是**字段级逐位复制(bit-wise copy)**。对于基本类型没问题,但对引用类型,只是复制了引用地址,新旧对象仍指向同一堆内存中的对象。
实现深拷贝的关键步骤
以一个含引用字段的类为例:
public class Person implements Cloneable {
private String name;
private Address address; // 引用类型,需深拷贝
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// 1. 调用父类 clone 得到浅拷贝对象
Person cloned = (Person) super.clone();
// 2. 对每个可变引用字段,手动克隆(要求其自身也支持克隆)
if (this.address != null) {
cloned.address = (Address) this.address.clone(); // 假设 Address 也实现了 Cloneable
}
return cloned;
}
}
- 必须让被引用的类(如
Address)也实现Cloneable并重写clone() - 对
null引用要判空,避免NullPointerException - 若引用类型是不可变类(如
String、Integer),无需克隆,直接赋值即可 - 数组需特殊处理:用
Arrays.copyOf()或对每个元素递归clone()
常见陷阱与注意事项
深拷贝容易出错的地方:
-
忘记重写
clone():只实现Cloneable会抛CloneNotSupportedException -
未声明
throws CloneNotSupportedException:编译报错 -
引用类型未实现克隆逻辑:比如
address.clone()若没重写,仍为浅拷贝 -
循环引用未处理:A→B→A 时可能无限递归,需缓存已克隆对象(可用
IdentityHashMap) -
final 字段无法在
clone()中重新赋值:设计时避免用final修饰需深拷贝的引用字段
替代方案建议(更可靠)
手写 clone() 易错且维护成本高。生产环境推荐以下方式:
-
构造器传参复制:提供带同类型参数的构造器,如
new Person(other),内部手动复制字段 -
序列化反序列化:利用
ObjectOutputStream+ObjectInputStream实现天然深拷贝(要求所有字段可序列化) -
使用工具库:如 Apache Commons Lang 的
SerializationUtils.clone(),或 MapStruct、Dozer(适合复杂对象图)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











