深拷贝与浅拷贝,就是这么简单

简介: 深拷贝与浅拷贝,就是这么简单

1.拷贝的概念

    在编程中,拷贝(或复制)是常见的操作之一。拷贝操作用于创建一个新对象或数据结构,使其具有与原对象或数据结构相同或部分相同的值。

    在进行拷贝操作时,常见的方式有浅拷贝和深拷贝。本文将重点讨论浅拷贝和深拷贝的概念、实现方式以及它们之间的区别。

2.浅拷贝

2.1. 浅拷贝的定义

    浅拷贝是指创建一个新对象,新对象的字段或属性与原对象相同。但对于原对象中的引用类型字段,浅拷贝只会复制其引用而不是实际的数据。

2.2. 浅拷贝的实现方式

    当使用浅拷贝时,新对象和原始对象共享相同的数据引用,意味着它们指向内存中相同的对象。

    在内存中,每个对象都被分配了一块内存空间。对象的字段存储在该内存空间中,并在字段中保存对其他对象的引用。当进行浅拷贝时,只复制了对象的字段值,而没有创建新的内存空间。

    假设有一个类 Person 如下:

class Person {
    private String name;
    private Address address;
    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
    // Getter and setter methods...
}

    其中包含一个 Address 类型的字段 address。现在假设我们有一个原始对象 person1,其中的 address 字段引用了同一个 Address 对象:

Person person1 = new Person("Alice", new Address("City", "Street"));

    当进行浅拷贝时,通过调用 person1.clone() 方法可以得到一个新对象 person2:

Person person2 = person1.clone();

    此时,person1 和 person2 是两个独立的对象,但它们的 name 字段和 address 字段引用相同的内存地址。

2.3 在内存中:

     address 字段在 person1 和 person2 中都指向同一个内存地址,即一个共享的 Address 对象。这意味着,当修改了这个共享的 Address 对象时,无论是通过 person1 还是 person2,修改都会反映在两个对象中。

    所以浅拷贝的效果就是对象之间共享相同的引用,对其中一个对象的修改会影响到其他对象。而如果需要实现完全独立的副本,可以使用深拷贝来创建对象的拷贝,并在其中复制引用类型的字段,确保每个副本都有自己独立的对象引用。

    Java中,可以通过以下方式实现浅拷贝:

    实现Cloneable接口,并重写clone()方法。

3. 深拷贝

3.1. 深拷贝的定义

    深拷贝是指创建一个新对象,新对象的所有字段或属性都是原对象的副本。无论是基本类型还是引用类型,都会被复制到新对象中。

3.2. 深拷贝的实现方式

    还是上面的例子,下面是深拷贝的实现:

class Person implements Cloneable {
    private String name;
    private Address address;
    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    @Override
    public Person clone() throws CloneNotSupportedException {
        Person clonedPerson = (Person) super.clone();
        // 创建一个新的 Address 对象并复制原始对象的 address 字段值
        clonedPerson.address = new Address(this.address.getCity(), this.address.getStreet());
        return clonedPerson;
    }
    // Getter and setter methods...
}
class Address {
    private String city;
    private String street;
    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
    // Getter and setter methods...
}

    在这个示例中,我们通过覆盖 clone() 方法并在其中手动创建一个新的 Address 对象来实现深拷贝。这样就可以确保每个副本都有自己独立的 Address 对象。

3.3 在内存中

    可以看到,person1 和 person2 是两个独立的对象,并且它们的 address 字段引用了不同的内存地址,即各自拥有独立的 Address 对象。因此,对其中一个对象的修改不会影响到另一个对象。

    需要注意的是,在实现深拷贝时,不仅要复制引用类型的字段,还要确保引用类型的字段也实现了可复制(深拷贝)的逻辑,以防止仍然存在共享的引用。

4. 深拷贝与浅拷贝的区别

  • 浅拷贝只复制对象引用,不复制实际数据;
  • 深拷贝会递归复制所有嵌套的对象和数据。

二维表展示对比

深拷贝 (Deep Copy) 浅拷贝 (Shallow Copy)
定义 创建一个新的对象,将原始对象的所有属性进行递归复制到新对象中 创建一个新的对象,将原始对象的属性的引用复制到新对象中
独立性 深拷贝后的对象和原始对象是完全独立的,对其中一个对象的修改不会影响另一个对象 浅拷贝后的对象和原始对象共享同一个属性对象,对其中一个对象的修改会影响另一个对象
对象关系 深拷贝后的对象和原始对象没有任何关联 浅拷贝后的对象和原始对象共享同一个属性对象
修改影响 对原始对象的修改不会影响深拷贝后的对象 对原始对象的修改会影响浅拷贝后的对象
对象复制 深拷贝会递归复制所有属性对象,创建一个完全独立的对象 浅拷贝只复制属性对象的引用,创建一个共享属性对象的新对象

    通过上述二维表的总结,可以清晰地看到深拷贝和浅拷贝的区别。

    深拷贝创建一个完全独立的对象,对原始对象的修改不会影响深拷贝后的对象;而浅拷贝创建一个共享属性对象的新对象,对原始对象的修改会影响浅拷贝后的对象。

    对于基本数据类型来说,两者一样,都会复制一份新的。

    如果还不太理解,举个例子看会不会好理解些:

  • 浅拷贝就像是在图书馆借阅一本书,并且与其他人共享同一本书。如果你标记了书中的某个页码或做了笔记,其他人看到的书也会有相同的变化。
  • 深拷贝则类似于每个人都有自己独立的书。你可以在你自己的书上做任何标记或笔记,而不会影响到其他人的书。

5. 原型模式与深浅拷贝的关系

    原型模式是一种创建型设计模式,它使用原型实例指定要创建的对象类型,并通过复制这个原型来创建新对象。在原型模式中,拷贝可以是浅拷贝或深拷贝,具体取决于如何实现原型对象的复制。

    在Java中,Cloneable接口就是原型模式的一种实现方式,它使用浅拷贝来复制对象。如果需要实现深拷贝,则需要在clone()方法中手动处理引用类型的字段或属性的拷贝。

    如果想有进一步的了解,可以参看我的上一篇博客

    链接: 设计模式之原型模式–超越实例化的魔法,从复制到创造的无限可能

6. 总结

  • 浅拷贝和深拷贝是常见的拷贝方式,用于创建对象副本。
  • 浅拷贝只复制引用。
  • 深拷贝复制整个对象及其嵌套的对象和数据。
相关文章
|
存储 人工智能 前端开发
深拷贝浅拷贝的区别?如何实现一个深拷贝?
深拷贝浅拷贝的区别?如何实现一个深拷贝?
487 0
|
算法 安全 PHP
密码学系列之二:密码学基本概念
密码学系列之二:密码学基本概念
2086 0
密码学系列之二:密码学基本概念
|
安全 数据安全/隐私保护
密码学系列之一:密码学的前世今生
密码学系列之一:密码学的前世今生
1319 0
|
存储 NoSQL Serverless
看 AgentRun 如何玩转记忆存储,最佳实践来了!
AgentRun 基于 Tablestore 提供三类智能体记忆能力:会话历史(维持单轮多轮上下文)、长期记忆(跨会话存储用户偏好等结构化信息)、会话状态(持久化任务进度等元数据),支持控制台配置与 SDK/SDK 集成。
572 0
|
存储 数据安全/隐私保护 开发者
Python深浅拷贝全解析:从原理到实战的避坑指南
在Python开发中,深浅拷贝是处理对象复制的关键概念。直接赋值仅复制引用,修改副本会影响原始数据。浅拷贝(如切片、copy方法)创建新容器但共享嵌套对象,适用于单层结构或需共享子对象的场景;而深拷贝(copy.deepcopy)递归复制所有层级,确保完全独立,适合嵌套结构或多线程环境。本文详解二者原理、实现方式及性能考量,帮助开发者根据实际需求选择合适的拷贝策略,避免数据污染与性能浪费。
720 1
|
存储 缓存 安全
Java集合框架(三):Map体系与ConcurrentHashMap
本文深入解析Java中Map接口体系及其实现类,包括HashMap、ConcurrentHashMap等的工作原理与线程安全机制。内容涵盖哈希冲突解决、扩容策略、并发优化,以及不同Map实现的适用场景,助你掌握高并发编程核心技巧。
|
前端开发 API 数据处理
什么是BFF API?
BFF(Backend For Frontend)API 是一种架构模式,旨在为特定的前端应用(如移动应用、桌面应用或网页应用)提供定制化的后端服务。通过这种方式,后端可以根据前端的具体需求和特性,提供最优化的数据和逻辑处理,从而提升用户体验和应用性能。
1075 6
|
API 开发者 Python
ISBN 数据查询 API :掌管书海信息的钥匙 如何调用?
探数平台的ISBN数据查询_专业版API致力于解决高校教辅书籍管理与交易中的痛点。通过输入13位ISBN编码,用户可快速获取图书名称、出版社、作者等20+维度信息,确保正版与版本准确性。该API包含图书基础信息查询和版本对比功能,适用于二手书交易、图书馆管理及电商场景。文档详细解析了ISBN编码规则、接口调用流程及Python示例代码,助力开发者高效集成,推动图书管理数字化升级。
1759 0
|
缓存 自然语言处理 JavaScript
JavaScript中闭包详解+举例,闭包的各种实践场景:高级技巧与实用指南
闭包是JavaScript中不可或缺的部分,它不仅可以增强代码的可维护性,还能在模块化、回调处理等场景中发挥巨大作用。然而,闭包的强大也意味着需要谨慎使用,避免潜在的性能问题和内存泄漏。通过对闭包原理的深入理解以及在实际项目中的灵活应用,你将能够更加高效地编写出简洁且功能强大的代码。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
前端开发 JavaScript UED

热门文章

最新文章