clone() 方法总返回 object 类型,因为 object.clone() 声明的返回类型是 object,非泛型也非协变;必须手动强转,且需实现 cloneable 接口,否则运行时抛 clonenotsupportedexception。

clone() 方法为什么总返回 Object 类型?
因为 Object.clone() 声明的返回类型就是 Object,不是泛型,也不是子类类型。JDK 没有在接口里做协变返回,所以你必须手动强转——哪怕你确定它就是 MyClass 实例。
常见错误现象:MyClass cloned = obj.clone(); 编译失败,提示“incompatible types”。
- 必须写成
MyClass cloned = (MyClass) obj.clone(); - 如果没实现
Cloneable,运行时抛CloneNotSupportedException,这个异常是 checked 的,不处理编译不过 - 强转失败(比如父类没实现但子类调了)会触发
ClassCastException,但通常发生在 clone 后字段引用错乱之后,更难排查
浅克隆下修改引用字段为什么会“污染”原对象?
浅克隆只复制对象本身字段值,对引用类型字段,复制的是地址值,不是新对象。所以原对象和克隆体共享同一份数组、ArrayList、自定义对象等。
使用场景:适合字段全是基本类型或不可变对象(如 String、LocalDateTime)的类;或者你明确希望共享某些状态。
立即学习“Java免费学习笔记(深入)”;
- 例如字段是
int[] data,克隆后cloned.data == original.data为true - 修改
cloned.data[0] = 99,original.data[0]也变成 99 - 若字段是
final List<string> tags</string>,浅克隆后仍共用同一个ArrayList,add/remove 都互相可见
深克隆必须手动处理所有可变引用字段
没有银弹。JDK 不提供自动深克隆,clone() 默认就是浅的,你要自己递归克隆每个可变引用字段。
性能影响:嵌套越深、引用对象越多,clone 越慢;还可能引发循环引用问题(如父子双向引用),不加判断会栈溢出。
- 对数组:用
Arrays.copyOf()或遍历新建 - 对
ArrayList:用new ArrayList(originalList)(前提是元素本身不可变,否则要逐个 clone) - 对自定义对象字段:必须确保其类也正确实现了
clone(),且调用field.clone(),不能直接赋值 - 避免序列化方式做深克隆(如
ObjectOutputStream),它要求所有字段可序列化,且性能差、破坏封装(访问 private 字段)
Cloneable 接口为什么是个空接口却必须实现?
它是 JVM 的一个标记机制:Object.clone() 在运行时检查 this 是否实现了 Cloneable,没实现就直接抛 CloneNotSupportedException。它不提供任何方法,也不参与多态,纯靠 JVM 特殊识别。
容易踩的坑:只重写了 clone() 却忘了 implements Cloneable,编译能过,运行必崩。
- IDE(如 IntelliJ)生成的
clone()方法默认不加implements Cloneable,得手动补 - 继承链中只要任意父类没实现
Cloneable,子类调用super.clone()就会失败 -
Cloneable不能被final类实现(无意义),但可以被接口继承——不过毫无作用,JVM 只认类是否实现
clone() 方法,而是理清哪些字段该深、哪些可浅、哪些根本不该克隆——这得看业务语义,不是语法能决定的。







