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

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

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. 总结

  • 浅拷贝和深拷贝是常见的拷贝方式,用于创建对象副本。
  • 浅拷贝只复制引用。
  • 深拷贝复制整个对象及其嵌套的对象和数据。
相关文章
|
9月前
|
前端开发 JavaScript
什么是深拷贝;深拷贝和浅拷贝有什么区别;深拷贝和浅拷贝有哪些方法(详解)
浅拷贝适用于只复制对象的第一层属性,且这些属性不是引用类型。深拷贝适用于需要完全独立的副本,包括对象和数组的嵌套结构。选择哪种拷贝方式取决于你的具体需求和场景。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
5月前
|
存储 数据安全/隐私保护 开发者
Python深浅拷贝全解析:从原理到实战的避坑指南
在Python开发中,深浅拷贝是处理对象复制的关键概念。直接赋值仅复制引用,修改副本会影响原始数据。浅拷贝(如切片、copy方法)创建新容器但共享嵌套对象,适用于单层结构或需共享子对象的场景;而深拷贝(copy.deepcopy)递归复制所有层级,确保完全独立,适合嵌套结构或多线程环境。本文详解二者原理、实现方式及性能考量,帮助开发者根据实际需求选择合适的拷贝策略,避免数据污染与性能浪费。
301 1
|
6月前
|
前端开发 JavaScript Java
浅拷贝与深拷贝区别之技术方案及应用实例解析
本文详解浅拷贝与深拷贝的区别、技术实现及应用场景,涵盖JavaScript与Python示例,并探讨性能优化与组件封装策略,助你掌握对象复制核心技巧,避免数据引用问题。
222 2
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
221 1
JavaScript中的原型 保姆级文章一文搞懂
|
存储 缓存 C语言
C语言:链表和数组有什么区别
C语言中,链表和数组是两种常用的数据结构。数组是一种线性结构,元素在内存中连续存储,通过下标访问,适合随机访问且大小固定的情况。链表由一系列不连续的节点组成,每个节点存储数据和指向下一个节点的指针,适用于频繁插入和删除操作的场景,链表的大小可以动态变化。
|
JSON JavaScript 安全
JS深浅拷贝
本文介绍了JavaScript中实现数据拷贝的四种方法:`Object.assign()`, 扩展运算符(`...`), `JSON.parse(JSON.stringify())` 和递归深拷贝。`Object.assign()`及扩展运算符对基本数据类型进行深拷贝,而对引用类型则进行浅拷贝。`JSON.parse(JSON.stringify())`对所有类型的数据都执行深拷贝,但存在一些限制如日期类型被转为字符串等。递归深拷贝则避免了这些问题,并支持循环引用,是一种更安全的选择。
663 0
JS深浅拷贝
|
前端开发
前端基础(四)_CSS层叠样式表_什么是css_css样式的引入方式_样式表的优先级_样式选择器
本文详细介绍了CSS(层叠样式表)的基本概念、语法规则、引入方式、样式表的优先级和样式选择器。文章解释了CSS的作用,展示了如何在HTML中通过行内样式、内部样式和外部样式引入CSS,讨论了不同CSS选择器的优先级和如何确定最终的样式应用。此外,还强调了使用`!important`规则时的优先级高于行内样式。
653 1
“深入探讨Java中的对象拷贝:浅拷贝与深拷贝的差异与应用“
“深入探讨Java中的对象拷贝:浅拷贝与深拷贝的差异与应用“
|
编译器 C++
深拷贝和浅拷贝介绍
这篇文章讨论了C++中的数据拷贝,特别是浅拷贝和深拷贝的概念。对于基本类型和简单对象,拷贝是按位复制,即浅拷贝,类似于`memcpy()`函数的效果。当类包含动态分配的内存或其他资源时,需要显式定义拷贝构造函数以实现深拷贝,确保对象间的独立性。文中通过一个自定义的变长数组类`Array`示例说明了深拷贝的必要性,并展示了不使用深拷贝可能导致的问题。通常,如果类有指针成员,大部分情况需要深拷贝;否则,浅拷贝可能就足够了。文章还提到了在创建对象时需要预处理的情况,如记录对象创建时间或计数,这也需要深拷贝。
364 0
|
存储 缓存 移动开发
前端开发中常用的存储方法(带解析)
前端存储方法包括Cookie、localStorage、sessionStorage、IndexedDB和已废弃的WebSQL。Cookie用于存储小量数据,每次请求时发送到服务器,可设置过期时间。localStorage和sessionStorage都是HTML5提供的,前者数据永久存储,后者会话关闭后清除。IndexedDB是存储大量结构化数据的数据库,支持索引和事务。WebSQL已废弃,但部分浏览器仍支持。Cache Storage用于缓存响应,提高离线访问性能,通过Service Worker控制。