深拷贝和浅拷贝:如何选择最适合你的对象复制技术?


深拷贝和浅拷贝:如何选择最适合你的对象复制技术?

文章插图

JAVA中的对象复制主要有三种方式:clone、深拷贝和浅拷贝 。这些技术对于Java开发人员来说非常重要,因为它们可以帮助开发人员管理复杂的数据结构 。本文将详细讨论这三种技术,包括其工作方式,优缺点以及使用时需要避免的陷阱 。
 
1. Java对象cloneJava对象的clone是一种创建对象副本的简单方法,它可以避免重新实例化对象并复制现有对象的字段 。当您需要创建一个与现有对象具有相同状态的新对象时,这种方法非常有用 。
1.1 clone() 方法在Java中,Object类提供了一个clone()方法,该方法会返回当前对象的一个副本 。由于clone()方法是从Object类继承而来的,所以它可以被任何Java对象调用 。Java中的clone()方法是一个浅拷贝,它只复制引用类型的地址,不会复制地址指向的对象 。
如果您想使用clone()方法,您的类必须实现Cloneable接口,该接口标记对象“可克隆” 。否则,您将会抛出
CloneNotSupportedException异常 。
下面是一个示例:
public class Person implements Cloneable {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}}在上面的示例中,Person类实现了Cloneable接口,并覆盖了Object类的clone()方法 。现在,我们可以使用该方法复制一个Person对象 。
1.2 浅拷贝在Java中,clone()方法是浅拷贝 。这意味着它仅复制基本数据类型和对象引用的值 。如果对象引用指向的是同一个对象,则副本和原始对象都将引用该对象的地址 。
下面是一个示例:
public class Person implements Cloneable {private String name;private int age;private Address address;public Person(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}}public class Address {private String street;private String city;public Address(String street, String city) {this.street = street;this.city = city;}}public class Main {public static void main(String[] args) {Address address = new Address("123 Main St", "Anytown");Person person1 = new Person("John Doe", 42, address);try {// Clone the personPerson person2 = (Person) person1.clone();// Modify the original object's fieldperson1.getAddress().setCity("New York");// Print out the fields for both objectsSystem.out.println(person1.getName() + ": " + person1.getAddress().getCity());System.out.println(person2.getName() + ": " + person2.getAddress().getCity());} catch (CloneNotSupportedException e) {e.printStackTrace();}}}在上面的示例中,我们创建了两个Person对象,并且将一个Address对象传递给他们 。然后,我们克隆了第一个Person对象并将其存储在另一个Person对象中 。接下来,我们修改原始对象的address字段,并打印出两个对象的地址以及城市字段 。
由于clone()方法是浅拷贝,所以person1和person2都引用同一个Address对象 。这意味着当我们修改其中一个对象的Address对象时,另一个对象也会收到影响 。
1.3 深拷贝深拷贝是一种复制对象及其所有子对象的技术 。与浅拷贝不同,深拷贝会复制对象的所有字段和子对象,而不是只复制引用类型的地址 。这意味着在深拷贝期间创建的副本与原始对象没有任何关联 。
 
有几种方法可以实现深拷贝 。其中一种方法是通过序列化和反序列化来完成 。另一种方法是使用递归方式遍历整个对象图,并复制每个对象及其子对象 。
下面是一个示例:
import java.io.*;public class Person implements Serializable {private String name;private int age;private Address address;public Person(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}public Person clone() throws IOException, ClassNotFoundException {// Serialize the objectByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(this);// Deserialize the objectByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);return (Person) ois.readObject();}}public class Address implements Serializable {private String street;private String city;public Address(String street, String city) {this.street = street;this.city = city;}}public class Main {public static void main(String[] args) {Address address = new Address("123 Main St", "Anytown");Person person1 = new Person("John Doe", 42, address);try {// Clone the personPerson person2 = person1.clone();// Modify the original object's fieldperson1.getAddress().setCity("New York");// Print out the fields for both objectsSystem.out.println(person1.getName() + ": " + person1.getAddress().getCity());System.out.println(person2.getName() + ": " + person2.getAddress().getCity());} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}}


推荐阅读