深拷贝和浅拷贝是关于复制对象时引用关系处理的两种不同策略。在理解深拷贝和浅拷贝的概念之前,首先需要了解对象引用和对象内部的数据存储。
对象引用和对象存储:
在 Java 中,对象变量存储的是对象的引用而不是对象本身。当一个对象被赋值给另一个对象变量时,实际上是复制了对象的引用,而不是对象的内容。这意味着两个对象变量可能引用同一个实际对象。、
classPerson { Stringname; Person(Stringname) { this.name=name; } } publicclassReferenceExample { publicstaticvoidmain(String[] args) { Personperson1=newPerson("John"); Personperson2=person1; // person2 引用了 person1 引用的对象person2.name="Doe"; System.out.println(person1.name); // 输出 Doe } }
在上述例子中,person2
和 person1
引用同一个 Person
对象,因此对 person2
的修改也会影响到 person1
。
浅拷贝(Shallow Copy):
浅拷贝是指只复制对象本身,而不复制对象内部的引用类型成员变量所引用的对象。简而言之,它只复制了对象的一层结构,而没有递归地复制对象内部的引用类型。
在 Java 中,可以通过实现 Cloneable
接口并覆盖 clone
方法来实现浅拷贝。
classAddress { Stringcity; Address(Stringcity) { this.city=city; } } classPersonimplementsCloneable { Stringname; Addressaddress; Person(Stringname, Addressaddress) { this.name=name; this.address=address; } protectedObjectclone() throwsCloneNotSupportedException { returnsuper.clone(); } } publicclassShallowCopyExample { publicstaticvoidmain(String[] args) throwsCloneNotSupportedException { Addressaddress=newAddress("New York"); Personperson1=newPerson("John", address); Personperson2= (Person) person1.clone(); person2.name="Doe"; person2.address.city="Los Angeles"; System.out.println(person1.name); // 输出 JohnSystem.out.println(person1.address.city); // 输出 Los Angeles } }
在上述例子中,person2
是通过 person1.clone()
得到的浅拷贝,当修改 person2
的属性时,person1
的属性也会受到影响。这是因为 address
是一个引用类型,浅拷贝只复制了引用,而没有复制引用指向的对象。
深拷贝(Deep Copy):
深拷贝是指在复制对象时,递归地复制对象内部的所有引用类型成员变量所引用的对象。深拷贝会创建一个新的对象,同时复制所有与之相关联的对象。
在 Java 中,实现深拷贝的方式可以是手动编写深拷贝方法,或者使用一些工具类,比如 Apache Commons Lang 库中的 SerializationUtils
或使用序列化和反序列化。
importorg.apache.commons.lang3.SerializationUtils; classAddress { Stringcity; Address(Stringcity) { this.city=city; } } classPersonimplementsjava.io.Serializable { Stringname; Addressaddress; Person(Stringname, Addressaddress) { this.name=name; this.address=address; } } publicclassDeepCopyExample { publicstaticvoidmain(String[] args) { Addressaddress=newAddress("New York"); Personperson1=newPerson("John", address); // 使用 SerializationUtils 进行深拷贝Personperson2=SerializationUtils.clone(person1); person2.name="Doe"; person2.address.city="Los Angeles"; System.out.println(person1.name); // 输出 JohnSystem.out.println(person1.address.city); // 输出 New York } }
在上述例子中,SerializationUtils.clone
利用了 Java 对象序列化的特性,将对象序列化为字节流,然后再反序列化为一个新的对象,实现了深拷贝。