1. 什么是拷贝?

在 Java 中,拷贝对象的过程可以分为两类:

  • 浅拷贝(Shallow Copy)
    仅复制对象本身的基本类型属性引用类型的地址,不会复制引用对象本身。

  • 深拷贝(Deep Copy)
    不仅复制对象本身,还会复制其引用类型所指向的对象,即完全复制一个“独立”的副本。


2. 浅拷贝(Shallow Copy)

📌 特点

  • 基本数据类型 → 值被复制。

  • 引用数据类型(对象、数组)→ 只复制引用地址,拷贝后的对象和原对象指向同一块内存。

  • 修改引用对象的内容时,两个对象会同时变化。

📌 实现方式

  1. 实现 Cloneable 接口并重写 clone() 方法(默认就是浅拷贝)。

  2. 使用构造方法赋值(只复制属性,不做深层次复制)。

📌 示例

class Address {
    String city;

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

class Person implements Cloneable {
    String name;
    int age;
    Address address;

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // 默认浅拷贝
    }
}

public class ShallowCopyDemo {
    public static void main(String[] args) throws Exception {
        Address addr = new Address("Beijing");
        Person p1 = new Person("Tom", 20, addr);
        Person p2 = (Person) p1.clone();

        System.out.println(p1.address.city); // Beijing
        System.out.println(p2.address.city); // Beijing

        p2.address.city = "Shanghai"; 
        System.out.println(p1.address.city); // Shanghai(浅拷贝影响了原对象)
    }
}

3. 深拷贝(Deep Copy)

📌 特点

  • 基本数据类型 → 值被复制。

  • 引用数据类型 → 会复制引用对象本身,两个对象完全独立。

  • 修改副本对象不会影响原始对象。

📌 实现方式

  1. 手动实现深拷贝
    clone() 中,除了调用 super.clone(),还对引用对象进行手动 clone

  2. 序列化与反序列化
    把对象写到流中,再读出来,就会得到一份新的对象,属于完全深拷贝。

  3. 使用第三方工具库(如 Apache Commons Lang 的 SerializationUtils.clone())。


📌 示例1:手动深拷贝

class Address implements Cloneable {
    String city;

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

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

class Person implements Cloneable {
    String name;
    int age;
    Address address;

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.address = (Address) address.clone(); // 手动克隆引用对象
        return cloned;
    }
}

public class DeepCopyDemo1 {
    public static void main(String[] args) throws Exception {
        Address addr = new Address("Beijing");
        Person p1 = new Person("Tom", 20, addr);
        Person p2 = (Person) p1.clone();

        p2.address.city = "Shanghai";

        System.out.println(p1.address.city); // Beijing(深拷贝互不影响)
        System.out.println(p2.address.city); // Shanghai
    }
}

📌 示例2:序列化深拷贝

import java.io.*;

class Address implements Serializable {
    String city;
    Address(String city) { this.city = city; }
}

class Person implements Serializable {
    String name;
    int age;
    Address address;
    Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
}

public class DeepCopyDemo2 {
    public static void main(String[] args) throws Exception {
        Address addr = new Address("Beijing");
        Person p1 = new Person("Tom", 20, addr);

        // 序列化 → 字节数组
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(p1);

        // 反序列化 → 新对象
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        Person p2 = (Person) ois.readObject();

        p2.address.city = "Shanghai";

        System.out.println(p1.address.city); // Beijing
        System.out.println(p2.address.city); // Shanghai
    }
}

4. 浅拷贝 vs 深拷贝 对比表

特性 浅拷贝 深拷贝
基本类型 拷贝值 拷贝值
引用类型 拷贝引用地址 拷贝新对象
是否独立 否,共享引用对象 是,完全独立
实现方式 Object.clone() 默认 手动 clone / 序列化 / 工具库
性能 较快 较慢(需要额外复制引用对象)
使用场景 只需要复制对象本身,不关心引用对象 必须保证副本和原对象互不影响

5. 总结

  • 浅拷贝:复制对象时,引用对象仍然共享,修改会互相影响。

  • 深拷贝:复制对象时,引用对象也会被复制,完全独立。

  • 实现方式

    • 浅拷贝:clone() 默认实现

    • 深拷贝:手动 clone() 引用对象 / 序列化反序列化 / 工具类

👉 一般情况下,如果对象中包含复杂的引用关系(如数组、集合、对象嵌套),推荐使用 深拷贝

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐