深拷贝和浅拷贝

深拷贝和浅拷贝是编程中常见的概念,尤其在处理对象复制时尤为重要。

它们之间的主要区别在于复制的深度和对象间的独立性。

浅拷贝(Shallow Copy)

浅拷贝是对象的逐位复制,它会创建一个新对象,该对象具有原始对象中值的精确副本。

但是,如果对象的任何字段是对其他对象的引用(即引用数据类型),则只复制引用地址,即复制内存地址。

这意味着浅拷贝后的两个对象会指向同一个内存地址,因此修改其中一个对象的属性,另一个对象的对应属性也会发生变化。

特点

  • 复制速度快,开销小。
  • 修改一个对象的引用类型属性会影响另一个对象。

实现方式

  • 在JavaScript中,使用Object.assign()方法可以实现浅拷贝,但需要注意,如果对象的属性值为引用类型,则实际上是浅拷贝。
  • 在Java中,如果类没有定义拷贝构造函数,则默认使用浅拷贝。

深拷贝(Deep Copy)

深拷贝不仅复制对象本身,还复制对象引用的其他对象,即它会为所有引用的对象开辟新的内存空间,实现真正内容上的拷贝。

这样,深拷贝后的两个对象是完全独立的,修改其中一个对象的属性不会影响另一个对象。

特点

  • 复制速度慢,开销大。
  • 修改一个对象的属性不会影响另一个对象。

实现方式

  • 在JavaScript中,可以使用JSON.parse(JSON.stringify(obj))实现深拷贝,但需要注意,这种方法不能处理循环引用、undefinedfunctionsymbolDate等特殊对象。

  • 手动实现递归方法也是常见的深拷贝方式,通过递归遍历对象,对每个属性进行拷贝,如果是引用类型则继续递归拷贝。

  • 在Java中,如果类实现了Cloneable接口并重写了clone()方法,可以实现深拷贝,但需要注意,在clone()方法内部,也需要对引用类型的成员变量进行深拷贝。

应用场景

  • 深拷贝

    • 保留原始数据的完整性,确保修改副本不会影响原始数据。
    • 处理含有循环引用的对象,避免在拷贝过程中出现无限循环。
    • 避免共享引用导致的意外修改,确保对象的独立性。
  • 浅拷贝

    • 复制简单的数据结构,如基本数据类型或简单的对象和数组。
    • 传递引用而不是副本,减少内存开销。
    • 缓存数据,避免频繁获取数据。

示例讲解

首先,我们来看一个浅拷贝的例子:

java 复制代码
class Person {
    private String name;
    private Address address;

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

    // Getters and Setters omitted for brevity

    @Override
    public String toString() {
        return "Person{name='" + name + "', address=" + address + "}";
    }

    // Shallow copy method
    public Person shallowCopy() {
        return new Person(this.name, this.address); // Note: address is copied by reference
    }
}

class Address {
    private String city;

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

    // Getters and Setters omitted for brevity

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

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

        Person person2 = person1.shallowCopy(); // Create a shallow copy

        System.out.println("Original: " + person1);
        System.out.println("Shallow Copy: " + person2);

        // Change the address in the shallow copy
        person2.getAddress().setCity("Los Angeles");

        // This will also affect the original because address is shared
        System.out.println("After modifying address in shallow copy:");
        System.out.println("Original: " + person1);
        System.out.println("Shallow Copy: " + person2);
    }
}

讲解

  • 在这个例子中,Person 类包含了一个 Address 类的引用。
  • shallowCopy() 方法创建了一个新的 Person 对象,但是 address 字段是通过引用复制的,所以 person1person2 共享同一个 Address 对象。
  • 当我们修改 person2address 时,person1address 也会受到影响,因为它们指向的是同一个对象。

深拷贝示例代码

接下来,我们看一个深拷贝的例子:

java 复制代码
class Person {
    private String name;
    private Address address;

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

    // Getters and Setters omitted for brevity

    @Override
    public String toString() {
        return "Person{name='" + name + "', address=" + address + "}";
    }

    // Deep copy method
    public Person deepCopy() {
        // Create a new Address object with the same city as the original
        Address newAddress = new Address(this.address.getCity());
        return new Person(this.name, newAddress); // Note: address is copied by value (i.e., a new object is created)
    }
}

class Address {
    private String city;

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

    // Getters and Setters omitted for brevity

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

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

        Person person2 = person1.deepCopy(); // Create a deep copy

        System.out.println("Original: " + person1);
        System.out.println("Deep Copy: " + person2);

        // Change the address in the deep copy
        person2.getAddress().setCity("Los Angeles");

        // This will not affect the original because each Person has its own Address object
        System.out.println("After modifying address in deep copy:");
        System.out.println("Original: " + person1);
        System.out.println("Deep Copy: " + person2);
    }
}

讲解

  • 在这个例子中,deepCopy() 方法不仅创建了一个新的 Person 对象,还创建了一个新的 Address 对象,并复制了原始 Address 对象的 city 字段。
  • 因此,person1person2 拥有不同的 Address 对象。
  • 当我们修改 person2address 时,person1address 不会受到影响,因为它们指向的是不同的对象。

最后

  • 浅拷贝:只复制对象本身,不复制对象中的引用类型字段所指向的对象。因此,浅拷贝后的两个对象会共享一些内部状态。

  • 深拷贝:不仅复制对象本身,还复制对象中的引用类型字段所指向的对象。因此,深拷贝后的两个对象是完全独立的。

相关推荐
长谷深风11113 小时前
好的 Tool Schema,不是字段越全越好
java·大数据·人工智能·ai agent·agent工作流·智能体设计·ai产品设计
IT 行者13 小时前
用 HiddenHttpMethodFilter 解决浏览器不支持 PUT/DELETE/PATCH 的问题
java·spring
晚安code13 小时前
Redis 内存淘汰策略实战:什么时候淘汰、怎么选、怎么防缓存击穿
java·redis·缓存
goyeer14 小时前
Liunx日志管理与journalctl
java·linux·运维·服务器·运维开发·信息化·信息化企业管理
tianyu23415 小时前
Java 正则表达式终极指南:从 Pattern 到 Matcher,从双重转义到性能优化,一篇全搞定
java·开发语言·正则表达式·group·find·pattern·matcher
Emily1568535987017 小时前
Emerson 1C31129G03 Analog Input Module
java·开发语言·前端·plc·emerson·1c31129g03·input module
就叫_这个吧1 天前
Java递归方法实现面包屑导航
java·开发语言
fīɡЙtīиɡ ℡1 天前
AI 应用系统设计
java·开发语言·人工智能
城管不管1 天前
重生——第十一次面试之挖财一面2026.8.19已OC
java·服务器·jvm·数据库·spring·面试·职场和发展
码匠许师傅1 天前
【C++ 面试真题】26. 聊聊 C++ 的智能指针
java·c++·面试