在Java中,对象复制是创建一个具有与现有实例相同状态的新对象的过程。历史上,自Java发展之初,当需要在不手动重新创建对象的情况下复制对象时,复制变得尤为重要。Java本身并没有提供通用的对象复制方法,取而代之的是使用clone()契约和复制构造器模式。
clone()方法被引入到Cloneable接口中,以提供对象克隆的标准机制,然而它的实现存在许多细微之处,常常会导致bug出现。
主要的问题是缺乏“开箱即用”的真正深度复制,以及在进行浅表克隆时可能出现的不可预测行为。复制构造器可以实现浅表和深度复制,但需要明确实现。
为了安全和正确地复制复杂对象,建议使用复制构造器或工厂方法,而clone()应该谨慎使用——仅在对象确实符合该契约的情况下使用。
示例代码:
// 通过clone()进行浅表克隆 public class Address implements Cloneable { String city; public Address(String city) { this.city = city; } @Override public Address clone() throws CloneNotSupportedException { return (Address) super.clone(); } } public class Person implements Cloneable { String name; Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override public Person clone() throws CloneNotSupportedException { Person copy = (Person) super.clone(); copy.address = address.clone(); // 深度复制address return copy; } } // 复制构造器 public class Person { String name; Address address; public Person(Person other) { this.name = other.name; this.address = new Address(other.address.city); } }
关键特性:
clone()要求实现Cloneable接口并重写clone方法。问题1:如果类没有实现Cloneable,调用clone()会发生什么?
如果对象没有实现Cloneable,clone()将抛出CloneNotSupportedException。
问题2:通过clone()进行的克隆默认是深度克隆吗?
不,默认实现仅为浅表克隆,所有对象引用都将按原样复制。
问题3:是否可以在不使用复制构造器的情况下进行深度克隆?
不,如果想控制过程,必须显式通过构造器或在clone()中手动定义嵌套对象的复制。
开发者在Order类中使用了标准的clone(),该类有一个List<Product>字段。结果,当修改副本中的产品列表时,原始产品也发生了改变,导致出现bug。
优点:
缺点:
公司为所有领域实体实现了复制构造器,并为复杂嵌套对象的克隆过程进行了额外的测试覆盖。
优点:
缺点: