java深拷贝需实现cloneable接口并重写public clone()方法,调用super.clone()后对每个可变引用字段手动克隆;不可变类型直接赋值,自定义类、数组、集合需分别处理;第三方类不支持时改用构造器或序列化。

Java中重写clone()实现深拷贝,核心是:在调用super.clone()获得对象副本后,对每个可变引用字段单独创建独立副本,而不是复用原引用。
必须先实现 Cloneable 接口
Cloneable 是一个空标记接口,不提供任何方法,但 JVM 会在底层检查它。没实现就调用 clone(),运行时一定抛 CloneNotSupportedException。编译器不会报错,容易遗漏。
- 接口声明要写在类定义里:
class Person implements Cloneable - 仅重写
clone()方法但不加implements Cloneable,等于没做
重写 clone() 方法要声明为 public 并处理异常
Object.clone() 是 protected 且声明抛出 CloneNotSupportedException。子类重写时必须提升访问权限,否则外部无法调用;也必须显式处理该异常。
- 推荐写法:
public Person clone() throws CloneNotSupportedException - 不要用空
catch吞掉异常,否则克隆失败却静默返回,排查困难 - 返回类型建议用具体类名(如
Person),而非Object,提升类型安全和可读性
对每个可变引用字段手动深拷贝
浅拷贝只复制字段值:基本类型直接复制,引用类型只复制地址。深拷贝要求所有可变引用字段都指向新对象。
- 不可变类型(String、LocalDateTime、Integer 等)无需处理,直接赋值即可
-
自定义类(如 Address):确保它也实现了
Cloneable并重写了clone(),然后在父类 clone 中调用:this.address = (Address) original.address.clone(); -
数组:用
Arrays.copyOf(arr, arr.length)或循环克隆每个元素 -
集合(ArrayList、HashMap 等):它们的
clone()只是浅拷贝容器结构,需新建集合并遍历添加克隆后的元素,例如:cloned.hobbies = new ArrayList(original.hobbies);(若元素不可变)或逐个clone()(若元素可变)
注意第三方类和泛型擦除的限制
不是所有类都支持克隆。比如 java.util.Date 虽可克隆,但很多第三方类未实现 Cloneable,强行调用会报运行时异常。
- 遇到无法克隆的字段,可改用构造器重建:
this.config = new Config(original.config.getProps()); - 或换序列化方案(要求所有字段类型可序列化)
- 泛型在运行时被擦除,集合里的元素类型无法自动推断,深拷贝时必须明确知道元素是否支持
clone(),不能依赖泛型参数做判断
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











