Object.clone()默认浅拷贝,深拷贝需手动递归克隆引用字段;关键在实现Cloneable、重写clone()并处理可变引用,或采用拷贝构造器等更安全替代方案。

Java 中 Object.clone() 默认只支持浅拷贝,要实现深拷贝需手动处理引用类型字段;关键在于理解 clone() 的契约、正确重写方法,并对可变引用对象递归克隆。
浅拷贝的实现步骤与要点
浅拷贝仅复制对象本身,其内部引用类型的字段仍指向原对象的同一实例。
- 目标类必须实现
Cloneable接口(否则调用clone()会抛CloneNotSupportedException) - 重写
public Object clone()方法,调用super.clone() - 返回类型建议改为具体类类型(利用协变返回类型提升可读性)
- 基本类型和不可变对象(如
String、Integer)无需额外处理
示例:
public class Person implements Cloneable {
private String name;
private int age;
private Address address; // 引用类型
@Override
public Person clone() {
try {
return (Person) super.clone(); // 浅拷贝:address 引用未变
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
深拷贝的核心思路与常见做法
深拷贝要求所有嵌套对象也生成新实例,避免原始对象与副本间共享状态。由于 Object.clone() 不自动递归克隆,需显式干预。
立即学习“Java免费学习笔记(深入)”;
- 对每个可变引用字段,在
clone()方法中调用其自身的clone()方法(前提是该类也支持克隆) - 若引用类型不支持克隆(如第三方类或未实现
Cloneable),改用构造器、静态工厂或序列化等方式创建副本 - 注意循环引用场景,避免无限递归;必要时用缓存记录已克隆对象
- 数组需单独调用
clone()(如arr.clone()是浅拷贝;若元素为引用类型且需深拷贝,须遍历再克隆)
改进后的深拷贝示例:
public class Person implements Cloneable {
private String name;
private int age;
private Address address;
@Override
public Person clone() {
try {
Person cloned = (Person) super.clone();
if (this.address != null) {
cloned.address = this.address.clone(); // 假设 Address 也实现了 Cloneable
}
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
替代方案与注意事项
直接依赖 clone() 易出错,实际开发中常采用更可控的方式。
- 使用拷贝构造器(Copy Constructor):清晰、安全、不依赖接口,推荐首选
- 使用静态工厂方法(如
from(Person src)):语义明确,便于扩展 - 利用序列化(如
ObjectOutputStream+ByteArrayInputStream):能自动完成深拷贝,但要求所有字段可序列化,性能较低,慎用于高频场景 - 注意
clone()不走构造器,可能绕过初始化逻辑(如单例校验、资源分配),需确保对象状态一致性
总结关键区别
浅拷贝是 super.clone() 的默认行为,快但共享引用;深拷贝需主动克隆每个可变引用字段,成本高但隔离彻底。是否需要深拷贝取决于业务对对象独立性的要求——若副本后续会修改内部状态,就必须深拷贝。


















