Object.clone()默认浅拷贝,深拷贝需手动克隆引用字段;类须实现Cloneable、重写public clone()并调用super.clone(),引用类型字段要递归clone,注意null判断及不可变对象无需克隆。

Java 中 Object.clone() 默认只支持浅拷贝,要实现深拷贝需手动处理引用类型字段。关键在于理解 clone() 的约束和主动干预引用对象的复制过程。
浅拷贝:直接调用 clone() 即可(需满足前提)
浅拷贝会复制对象本身,但其内部的引用类型字段仍指向原对象的同一份实例。
- 类必须实现
Cloneable接口(否则抛CloneNotSupportedException) - 重写
clone()方法,并将访问修饰符改为public - 在方法体内调用
super.clone(),它返回的是当前对象的逐字段复制(基本类型值复制,引用类型地址复制)
示例:
class Person implements Cloneable {String name;
Address address; // 引用类型
public Person clone() {
try {
return (Person) super.clone(); // 浅拷贝:address 字段仍指向原对象的 address 实例
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
深拷贝:在 clone() 中递归克隆引用字段
深拷贝要求所有嵌套对象也生成新实例。若引用字段所属类也支持克隆(即实现了 Cloneable 并重写了 clone()),可在父类的 clone() 方法中手动调用其 clone()。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 确保被引用的类(如
Address)也实现Cloneable并提供public clone()方法 - 在
Person.clone()中,对address字段调用address.clone(),并赋值给副本对象 - 若引用字段为
null,注意判空避免NullPointerException
改进后的 Person.clone():
try {
Person cloned = (Person) super.clone();
if (this.address != null) {
cloned.address = this.address.clone(); // 深拷贝 address
}
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
注意事项与常见陷阱
-
Cloneable是标记接口,不包含clone()方法;仅实现它不会自动获得克隆能力,必须重写clone() -
super.clone()是 native 方法,由 JVM 实现,它执行的是“字段级复制”,不是构造器调用 - 数组是特殊对象:一维基本类型数组(如
int[])调用clone()得到的是深拷贝效果;一维引用类型数组(如String[])clone()后仍是浅拷贝(数组元素引用未变) - 若类含不可变字段(如
String、包装类),无需额外克隆——它们本身不可变,共享安全
替代方案建议(更清晰可控)
基于构造器或静态工厂方法实现拷贝往往比重写 clone() 更直观、不易出错:
- 提供带同类型参数的构造器:
public Person(Person other) { this.name = other.name; this.address = new Address(other.address); } - 使用序列化(适用于可序列化类):将对象写入字节数组再反序列化,天然实现深拷贝(但性能低、有局限)
- 借助工具库如 Apache Commons Lang 的
SerializationUtils.clone()或 Jackson/Gson 做 JSON 序列化再反序列化(适合简单 POJO)
不复杂但容易忽略:浅拷贝与深拷贝的选择,取决于业务是否允许原始对象与副本共享状态。共享可能引发意料外的修改,尤其在多线程或复杂嵌套场景下。

















