Java深拷贝与浅拷贝

在Java中,对象的拷贝是一个常见的操作。拷贝可以分为浅拷贝和深拷贝两种类型。对于不同类型的拷贝,我们需要了解其原理和使用方法,以便在实际应用中选择最适合的方式。

什么是浅拷贝?

浅拷贝是指在拷贝对象时,只复制对象的引用,而不复制引用指向的对象本身。如下图所示:

class Person {
    String name;
 
    public Person(String name) {
        this.name = name;
    }
}
 
public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("Alice");
        Person person2 = person1;  // 浅拷贝
 
        person2.name = "Bob";
 
        System.out.println(person1.name);  // 输出 "Bob",person1和person2指向同一个对象
        System.out.println(person2.name);  // 输出 "Bob"
    }
}

在上面的例子中,我们创建了一个Person类,拥有一个name属性。我们首先创建了一个person1对象,并将其name属性设置为"Alice"。然后,我们将person2指向了person1,这是一个浅拷贝的过程。修改person2name属性为"Bob"后,我们发现person1name属性也被修改为"Bob"。

这是因为person2实际上是指向了person1的引用,它们共享同一个对象。所以,当我们通过person2修改对象的属性时,实际上是修改了同一个对象,从而导致person1的属性也发生了变化。

什么是深拷贝?

与浅拷贝不同,深拷贝是指在拷贝对象时,不仅复制对象的引用,还复制引用指向的对象本身。如下图所示:

class Person implements Cloneable {
    String name;
 
    public Person(String name) {
        this.name = name;
    }
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
 
public class Main {
    public static void main(String[] args) {
        try {
            Person person1 = new Person("Alice");
            Person person2 = (Person) person1.clone();  // 深拷贝
 
            person2.name = "Bob";
 
            System.out.println(person1.name);  // 输出 "Alice"
            System.out.println(person2.name);  // 输出 "Bob"
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

在上面的例子中,我们对Person类实现了Cloneable接口,并重写了clone()方法。在main()方法中,我们通过调用clone()方法进行了深拷贝操作。

在深拷贝的过程中,我们通过调用super.clone()来实现对象的拷贝。这里需要注意的是,clone()方法是一个受保护的方法,我们需要进行异常处理。

通过深拷贝,我们创建了一个新的对象person2,它的name属性被设置为"Bob"。与浅拷贝不同,我们修改person2的属性后,并不会影响到person1的属性。

深拷贝的实现方式

在上面的例子中,我们使用了Object类中的clone()方法来实现深拷贝。然而,clone()方法只是完成了对象的拷贝,对于引用类型的属性,仍然是浅拷贝。为了实现真正的深拷贝,我们需要对引用类型的属性进行拷贝。

1. 使用构造函数进行拷贝

一种实现深拷贝的方式是通过使用构造函数来拷贝对象的属性。具体步骤如下:

  1. 在目标类中定义与源类属性一致的构造函数。
  2. 在构造函数中,将源对象的属性值赋给目标对象的属性。
class Person {
    String name;
 
    public Person(String name) {
        this