重写 clone() 并不优雅,它是 Java 早期有缺陷的设计;应优先采用拷贝构造器、静态工厂或 record 等更安全可控的深拷贝方式。

重写 clone() 方法本身并不“优雅”,它本质是 Java 早期设计中一个有缺陷的机制:绕过构造器、与 final 字段冲突、类型不安全、易漏字段。所谓“优雅”,其实是用最小侵入、最可控、最不易出错的方式达成深拷贝目标——而**不是执着于把 clone() 写得多漂亮**。
先确保基础合规,避免运行时崩溃
这是所有后续操作的前提,缺一不可:
- 类必须声明
implements Cloneable(空接口,纯标记作用) -
clone()方法必须是public(否则外部无法调用) - 方法签名建议用协变返回类型,比如
public Person clone(),而非public Object clone(),提升类型安全和可读性 - 必须在方法体内调用
super.clone(),这是 JVM 提供的原始副本创建逻辑 - 异常处理推荐用
try-catch包裹并转为AssertionError或RuntimeException(因为已实现Cloneable,理论上不会抛出CloneNotSupportedException)
对引用字段做精准深拷贝,不偷懒、不假设
浅拷贝的坑就在这里:super.clone() 只复制字段值,对 List、Address、数组等引用类型,只是复制了地址。你要主动切断共享:
- 不可变对象(
String、Integer、LocalDateTime等)直接赋值,无需任何操作 - 标准集合(
ArrayList、HashMap)不能调list.clone()—— 它仍是浅的。应新建实例并填充,如new ArrayList(this.hobbies)(元素不可变时安全) - 自定义对象(如
Address)必须确保它自己也正确实现了clone(),然后显式调用:this.address = this.address.clone() -
数组字段:若为对象数组,
Arrays.copyOf()是浅的,需遍历每个元素并克隆;基本类型数组可直接用Arrays.copyOf()
避开 clone() 的硬伤,考虑更现代的替代方案
很多场景下,“重写 clone()” 并非最优解,反而增加维护成本和出错概率:
立即学习“Java免费学习笔记(深入)”;
-
拷贝构造器:写一个
public Person(Person other),内部对每个字段做明确初始化。语义清晰、支持final字段、IDE 可自动补全、调试友好 -
静态工厂方法:如
public static Person copyOf(Person other),逻辑集中、命名自解释、可加校验或默认值处理 - record 类(Java 14+):天然不可变,若需“副本”,直接 new 一个新 record 实例即可,无共享风险
-
序列化工具(慎用):如 Apache Commons Lang 的
SerializationUtils.clone(),通用但要求所有字段可序列化,且性能差、transient字段丢失、Android 不兼容
最后提醒几个容易忽略的关键点
这些细节决定深拷贝是否真正可靠:
- 嵌套层级深时,容易漏掉某一层引用(比如只克隆了
Person → Address,却忘了Address → City),建议画简单对象图辅助检查 - 循环引用(A→B→A)会导致手动克隆栈溢出,序列化也可能失败,需额外引入引用跟踪机制
- 含资源型字段(
Thread、Connection、ExecutorService)的对象,克隆本身无意义,应使用 builder 或 factory 重建 - Lombok 的
@Data不生成clone(),若混用,极易误以为已有深拷贝能力


















