实现克隆需实现Cloneable接口并重写clone()方法,1. 默认为浅克隆,仅复制基本类型和引用地址;2. 深克隆需手动复制引用对象;3. 推荐使用拷贝构造函数或序列化替代以避免问题。
在Java中实现对象的克隆功能,核心方式是通过实现 Cloneable 接口并重写 Object 类中的 clone() 方法。虽然Java提供了原生支持,但使用时需要注意深拷贝与浅拷贝的区别,以及正确处理可变字段。
启用克隆:实现 Cloneable 接口
Cloneable 是一个标记接口,不包含任何方法。实现该接口的作用是向 JVM 表明该类允许被克隆。如果不实现它,调用 clone() 方法会抛出 CloneNotSupportedException。
基本步骤如下:
- 让类实现 Cloneable 接口
- 重写 Object 的 clone() 方法,并将其访问级别改为 public
- 在方法内部调用 super.clone()
// 示例:实现浅克隆public class Person implements Cloneable { private String name; private int age; @Override public Person clone() { try { return (Person) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(); // 不应发生 } }}
浅克隆 v
s 深克隆
默认的 clone() 方法执行的是浅克隆,即只复制对象的基本类型字段和引用地址,而不复制引用对象本身。如果原对象包含其他对象(如数组、集合、自定义对象),克隆后的新对象将共享这些引用。
若需要完全独立的副本,必须实现深克隆。
-
浅克隆问题示例:两个对象共用同一个地址对象,修改一个会影响另一个
-
解决办法:在 clone() 方法中手动克隆引用类型的字段
// 示例:实现深克隆public class Person implements Cloneable { private String name; private Address address; // 假设 Address 也可克隆 @Override public Person clone() { try { Person cloned = (Person) super.clone(); cloned.address = this.address.clone(); // 假设 Address 也实现了 clone return cloned; } catch (CloneNotSupportedException e) { throw new AssertionError(); } }}
替代方案:构造函数或序列化
除了 clone(),还有更安全、清晰的方式创建对象副本:
-
拷贝构造函数:public Person(Person other) { ... }
-
工厂方法:如 from(person)
-
序列化反序列化:适用于复杂对象且所有字段都可序列化的情况
这些方法避免了 clone() 的诸多陷阱,比如保护性拷贝缺失、构造器未执行等问题。
基本上就这些。Java 的 clone 机制虽然存在,但使用需谨慎。推荐优先考虑拷贝构造函数或现代序列化工具(如 Jackson、JSON 序列化)来实现对象复制,代码更清晰且不易出错。