在Java中,shallow copy(浅拷贝)是指复制对象时,仅复制嵌套对象的引用,而不是对象本身。因此,对嵌套对象的更改将反映在副本和原始对象中。Deep copy(深拷贝)意味着创建所有嵌套对象的新独立副本。
class Address implements Cloneable { String city; Address(String city) { this.city = city; } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } // 使用 Person p1 = new Person("Ivan", new Address("Moscow")); Person p2 = (Person) p1.clone(); p2.address.city = "Petersburg"; System.out.println(p1.address.city); // 输出"Petersburg" — 浅拷贝
class Address implements Cloneable { String city; Address(String city) { this.city = city; } protected Object clone() throws CloneNotSupportedException { return new Address(this.city); } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = (Address) address.clone(); return cloned; } }
深拷贝使得可以创建一个完全独立的对象副本。
问题: 可以使用clone()方法来保证任意复杂对象的深拷贝吗?
答案: 不可以,标准的clone()只进行浅拷贝(shallow copy)。对于深拷贝,必须在所有嵌套类中重写clone()并明确克隆所有引用字段。此外,许多集合和标准类不支持深度克隆。
故事
用户和他们的地址集合通过clone()方法进行克隆而没有进行深拷贝。修改一个用户的地址后,另一个用户的地址也发生了变化,因为复制的是引用。数据在数据库中互相"泄露"。
故事
在序列化复杂对象时使用了包含嵌套集合的clone(),而不是深拷贝。恢复序列化后,数据不一致,导致了NPE。
故事
在REST API中,DTO对象默认通过BeanUtils.copyProperties()进行克隆,导致同一个集合在不同客户端之间被共享。因此,用户能够看到和编辑他人的数据。