Skip to content

深拷贝和浅拷贝区别

1. 什么是浅拷贝?浅拷贝?

浅拷贝是指复制对象时,只复制对象本身,而不复制对象引用的其他对象。浅拷贝后,新对象和原对象共享引用的其他对象。

深拷贝是指复制对象时,不仅复制对象本身,还递归地复制对象引用的其他对象。深拷贝后,新对象和原对象完全独立。

深拷贝和浅拷贝是在进行对象的复制时常用的两种方式,它们有以下区别:

  1. 拷贝的程度:
    • 浅拷贝只拷贝对象的引用,不创建新的对象实例。拷贝后的对象与原始对象共享同一份数据,对其中一个对象的修改会影响到另一个对象。
    • 深拷贝创建一个全新的对象实例,并将原始对象的所有属性值复制到新对象中。拷贝后的对象与原始对象是独立的,对任一对象的修改不会影响另一个对象。
  2. 对象引用:
    • 浅拷贝只复制对象引用,新旧对象仍然指向同一块内存空间,修改其中一个对象的属性会影响另一个对象。
    • 深拷贝会复制对象本身以及对象引用指向的其他对象,所有对象的引用都将指向全新的内存空间。
  3. 性能开销:
    • 浅拷贝的性能开销较小,因为仅复制对象的引用。
    • 深拷贝的性能开销较大,因为需要创建新的对象实例并复制所有属性。

通常情况下,当我们需要复制一个对象并希望新对象与原始对象互不影响时,应使用深拷贝。而浅拷贝更适用于那些对象结构较简单、不包含引用类型成员变量或不需要独立修改的情况。

示例:浅拷贝

java
/**
 * @Auth:TianMing
 * @Description:浅拷贝
 */
public class ShallowCopyExample implements Cloneable {
    private int id;
    private String name;
    private Address address;

    public ShallowCopyExample(int id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

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

    public static void main(String[] args) {
        Address address = new Address("123 Main St", "City");
        ShallowCopyExample original = new ShallowCopyExample(1, "John", address);

        try {
            ShallowCopyExample copy = (ShallowCopyExample) original.clone();
            System.out.println("Original Address: " + original.address);
            System.out.println("Copy Address: " + copy.address);

            // 修改地址
            copy.address.setStreet("456 New St");
            System.out.println("After modification:");
            System.out.println("Original Address: " + original.address);
            System.out.println("Copy Address: " + copy.address);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

class Address {
    private String street;
    private String city;

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

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    @Override
    public String toString() {
        return "Address{" + "street='" + street + '\'' + ", city='" + city + '\'' + '}';
    }
}

输出:

复制

plain
Original Address: Address{street='123 Main St', city='City'}
Copy Address: Address{street='123 Main St', city='City'}
After modification:
Original Address: Address{street='456 New St', city='City'}
Copy Address: Address{street='456 New St', city='City'}

示例:深拷贝

java
/**
 * @Auth:TianMing
 * @Description:深拷贝
 */
public class DeepCopyExample implements Cloneable {
    private int id;
    private String name;
    private Address address;

    public DeepCopyExample(int id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        DeepCopyExample copy = (DeepCopyExample) super.clone();
        copy.address = (Address) this.address.clone(); // 深拷贝地址
        return copy;
    }

    public static void main(String[] args) {
        Address address = new Address("123 Main St", "City");
        DeepCopyExample original = new DeepCopyExample(1, "John", address);

        try {
            DeepCopyExample copy = (DeepCopyExample) original.clone();
            System.out.println("Original Address: " + original.address);
            System.out.println("Copy Address: " + copy.address);

            // 修改地址
            copy.address.setStreet("456 New St");
            System.out.println("After modification:");
            System.out.println("Original Address: " + original.address);
            System.out.println("Copy Address: " + copy.address);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

class Address implements Cloneable {
    private String street;
    private String city;

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

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

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    @Override
    public String toString() {
        return "Address{" + "street='" + street + '\'' + ", city='" + city + '\'' + '}';
    }
}

输出:

复制

plain
Original Address: Address{street='123 Main St', city='City'}
Copy Address: Address{street='123 Main St', city='City'}
After modification:
Original Address: Address{street='123 Main St', city='City'}
Copy Address: Address{street='456 New St', city='City'}

3. 浅拷贝和深拷贝的区别是什么?

  • 浅拷贝:只复制对象本身,引用的其他对象不复制,新对象和原对象共享引用的其他对象。
  • 深拷贝:递归地复制对象及其引用的所有对象,新对象和原对象完全独立。

4. 如何实现深拷贝和浅拷贝?

  • 浅拷贝:使用 Object.clone() 方法,或者通过构造方法或手动复制字段
  • 深拷贝:手动实现深拷贝,或者使用序列化。

5. 深拷贝的实现方式有哪些?

  1. 手动实现:手动实现深拷贝是最直接的方法,通过逐个复制对象的字段来实现。这种方法需要对对象的内部结构有详细的了解,并且需要递归地复制所有引用的对象。。
  2. 序列化:序列化是另一种实现深拷贝的方法。通过将对象序列化为字节流,然后再反序列化为新对象,可以实现深拷贝。这种方法适用于所有实现了 Serializable 接口的类。
  3. 第三方库:一些第三方库(如 Apache Commons Lang)提供了深拷贝的功能,可以简化代码。

示例(手动实现深拷贝):

java
/**
 * @Auth:TianMing
 * @Description: 手动实现深拷贝
 */
public class DeepCopyExample implements Cloneable {
    private int id;
    private String name;
    private Address address;

    public DeepCopyExample(int id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 手动实现深拷贝
        DeepCopyExample copy = (DeepCopyExample) super.clone();
        copy.address = (Address) this.address.clone(); // 深拷贝地址
        return copy;
    }

    public static void main(String[] args) {
        Address address = new Address("123 Main St", "City");
        DeepCopyExample original = new DeepCopyExample(1, "John", address);

        try {
            DeepCopyExample copy = (DeepCopyExample) original.clone();
            System.out.println("Original Address: " + original.address);
            System.out.println("Copy Address: " + copy.address);

            // 修改地址
            copy.address.setStreet("456 New St");
            System.out.println("After modification:");
            System.out.println("Original Address: " + original.address);
            System.out.println("Copy Address: " + copy.address);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

class Address implements Cloneable {
    private String street;
    private String city;

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

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

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    @Override
    public String toString() {
        return "Address{" + "street='" + street + '\'' + ", city='" + city + '\'' + '}';
    }
}

示例:序列化实现

java
import java.io.*;
/**
 * @Auth:TianMing
 * @Description: 序列化实现深拷贝
 */
public class DeepCopyWithSerialization {
    public static <T extends Serializable> T deepCopy(T obj) throws IOException, ClassNotFoundException {
        // 将对象序列化为字节流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(obj);

        // 将字节流反序列化为新对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        return (T) objectInputStream.readObject();
    }

    public static void main(String[] args) {
        Address address = new Address("123 Main St", "City");
        DeepCopyExample original = new DeepCopyExample(1, "John", address);

        try {
            DeepCopyExample copy = DeepCopyWithSerialization.deepCopy(original);
            System.out.println("Original Address: " + original.address);
            System.out.println("Copy Address: " + copy.address);

            // 修改地址
            copy.address.setStreet("456 New St");
            System.out.println("After modification:");
            System.out.println("Original Address: " + original.address);
            System.out.println("Copy Address: " + copy.address);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

示例(使用第三方库 Apache Commons Lang实现):

java
import org.apache.commons.lang3.SerializationUtils;

/**
 * @Auth:TianMing
 * @Description: 第三方库实现深拷贝
 */
public class DeepCopyWithApacheCommons {
    public static <T> T deepCopy(T obj) {
        return SerializationUtils.clone(obj);
    }

    public static void main(String[] args) {
        Address address = new Address("123 Main St", "City");
        DeepCopyExample original = new DeepCopyExample(1, "John", address);

        DeepCopyExample copy = DeepCopyWithApacheCommons.deepCopy(original);
        System.out.println("Original Address: " + original.address);
        System.out.println("Copy Address: " + copy.address);

        // 修改地址
        copy.address.setStreet("456 New St");
        System.out.println("After modification:");
        System.out.println("Original Address: " + original.address);
        System.out.println("Copy Address: " + copy.address);
    }
}

更新: 2025-04-15 19:30:37
原文: https://www.yuque.com/tulingzhouyu/db22bv/ni0qchop1a9934tm

短视频

没想到一个很简单的面试题,难住了一位工作3年的粉丝,大家好,我是JJ

最近有粉丝在后台留言问深拷贝与浅拷贝有什么区别,工作三年了这个都不知道,有点不应该啊。

深拷贝和浅拷贝是对象复制中的两个关键概念,它们主要区别在于对象的内部数据是否独立

浅拷贝只复制对象自身,而不复制其内部引用的对象

也就是说,浅拷贝后的对象与原始对象共享同一个内部引用

如果修改其中一个对象的内部数据,另外一个对象也会受到影响

而深拷贝不仅会复制对象自身,还会递归地复制所有内部引用的对象,从而创建完全独立的副本

这样,深拷贝后的对象和原始对象之间没有任何共享的数据修改其中一个对象的内部数据不会影响到另一个对象

简单来说,浅拷贝结果是对象之间共享内部引用,而深拷贝结果是每个对象都有独立的内部数据副本。

更新: 2024-06-13 21:22:40
原文: https://www.yuque.com/tulingzhouyu/db22bv/rgm60f0zoraq02ts