java中实现浅克隆需三步:类实现cloneable接口(标记许可)、重写public clone()方法、方法内调用super.clone();cloneable无方法,仅触发jvm检查,未实现则抛clonenotsupportedexception;super.clone()逐字段拷贝,基本类型和不可变引用独立,可变引用共享同一实例。

直接用 clone() 方法实现浅克隆,核心就三步:类声明实现 Cloneable 接口、重写 public clone() 方法、在方法里调用 super.clone()。标记接口本身不提供任何方法,它只起“许可通行证”的作用——告诉 JVM“这个类允许被克隆”,否则调用 clone() 会立刻抛出 CloneNotSupportedException。
浅克隆的正确写法
必须同时满足以下条件,super.clone() 才能成功执行:
- 类显式声明
implements Cloneable(哪怕接口是空的) -
clone()方法访问权限改为public(原生是protected,外部无法调用) - 方法体中调用
super.clone(),并处理CloneNotSupportedException(通常用 try-catch 包裹或向上声明) - 建议使用协变返回类型,比如返回
Person而非Object,避免强制转型
Cloneable 接口的真实角色
它不是功能接口,也不定义任何行为。它的唯一作用是参与 JVM 的运行时检查:
- 当
Object.clone()被调用时,JVM 会检查对象所属类是否实现了Cloneable - 没实现 → 直接抛
CloneNotSupportedException - 实现了 → 允许执行底层内存拷贝,生成新对象实例
- 换句话说:没有它,
clone()连门都进不去;有了它,也只是开了门,具体怎么克隆还得靠super.clone()
浅克隆实际复制了什么
super.clone() 做的是字段级逐位拷贝:
- 基本类型(
int、boolean等)和不可变引用(如String、Integer)→ 值完全独立,互不影响 - 可变引用类型(如自定义对象、
ArrayList、数组)→ 只复制引用地址,新旧对象指向堆中同一个实例 - 所以修改克隆对象里的
address.city,原对象的address.city也会变——它们用的是同一个Address对象
常见错误与规避点
这几个坑新手容易踩:
- 只加
implements Cloneable,但没重写clone()方法 → 编译通过,运行时报错(因为外部仍调不到protected方法) - 重写了
clone()却没改public→ 子类或外部类无法调用 - 字段含
final引用类型(如final List<string> tags</string>)→super.clone()无法重新赋值,会编译失败,需在clone()中手动新建并赋值 - 忽略继承链:若父类没实现
Cloneable或没正确重写clone(),子类调用super.clone()可能返回错误类型或抛异常











