Java 中对象的复制:深拷贝与浅拷贝

在 Java 编程中,复制对象是一项常见的任务,尤其是在处理复杂数据结构时。对象的复制通常可以通过浅拷贝深拷贝两种方式来实现。本文将深入探讨这两种拷贝方式,并通过代码示例进行说明。

什么是浅拷贝?

浅拷贝是指创建一个新对象,其内容与原对象相同,但对于子对象(引用类型),新对象和原对象仍然指向同一块内存区域。这意味着如果子对象的状态在其中一个对象中发生变化,另一个对象也会受到影响。

浅拷贝示例

下面是一个简单的示例,演示如何使用 Java 的 clone() 方法进行浅拷贝:

class Address {
    String city;

    public Address(String city) {
        this.city = city;
    }
}

class Person implements Cloneable {
    String name;
    Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("New York");
        Person person1 = new Person("Alice", address);
        Person person2 = (Person) person1.clone();

        System.out.println("Before changing address:");
        System.out.println("person1 address: " + person1.address.city);
        System.out.println("person2 address: " + person2.address.city);

        // 改变 person1 的地址
        person1.address.city = "Los Angeles";

        System.out.println("After changing address:");
        System.out.println("person1 address: " + person1.address.city);
        System.out.println("person2 address: " + person2.address.city);
    }
}

运行结果

Before changing address:
person1 address: New York
person2 address: New York
After changing address:
person1 address: Los Angeles
person2 address: Los Angeles

如上所示,修改 person1 的地址后,person2 的地址也发生了变化。这就是浅拷贝的特征。

什么是深拷贝?

深拷贝则是指创建一个新对象,及其所有子对象均为新创建的对象。也就是说,新对象和原对象在内存中是完全独立的,彼此的状态变化不会互相影响。

深拷贝示例

下面是通过实现 Serializable 接口和使用对象流来实现深拷贝的示例:

import java.io.*;

// Address class
class Address implements Serializable {
    String city;

    public Address(String city) {
        this.city = city;
    }
}

// Person class
class Person implements Serializable {
    String name;
    Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    // 深拷贝
    public Person deepClone() throws IOException, ClassNotFoundException {
        // 将对象写入流
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(this);
        
        // 从流中读取对象
        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        
        return (Person) in.readObject();
    }
}

public class DeepCopyExample {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Address address = new Address("New York");
        Person person1 = new Person("Alice", address);
        Person person2 = person1.deepClone();

        System.out.println("Before changing address:");
        System.out.println("person1 address: " + person1.address.city);
        System.out.println("person2 address: " + person2.address.city);

        // 改变 person1 的地址
        person1.address.city = "Los Angeles";

        System.out.println("After changing address:");
        System.out.println("person1 address: " + person1.address.city);
        System.out.println("person2 address: " + person2.address.city);
    }
}

运行结果

Before changing address:
person1 address: New York
person2 address: New York
After changing address:
person1 address: Los Angeles
person2 address: New York

此示例中,修改 person1 的地址并未影响 person2 的地址,表现出了深拷贝的特征。

序列图解析

我们可以通过序列图更好地理解深拷贝过程。以下是深拷贝的序列图:

sequenceDiagram
    participant A as Person1
    participant B as Person2
    participant C as ObjectOutputStream
    participant D as ObjectInputStream

    A->>C: Serialize Person1
    C->>C: Write Object State
    C->>B: Output Stream
    D->>C: Input Stream
    D->>B: Deserialize to Person2

实体关系图

在我们的例子中,Person 类和 Address 类之间的关系可以用一个实体关系图表示:

erDiagram
    PERSON {
        String name
    }
    ADDRESS {
        String city
    }
    PERSON ||--o{ ADDRESS : has

总结

在 Java 中,了解浅拷贝和深拷贝的区别非常重要。浅拷贝适用于那些对象间共享状态没有负面影响的情况,而深拷贝则适用于需要完全独立的对象副本的情况。根据具体需求选择合适的拷贝方式,可以极大地提升程序的健壮性和可维护性。

希望通过本篇文章,你对 Java 的对象复制有了更深入的理解!如有任何问题,欢迎交流讨论。