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

news2024/11/18 11:22:01

目录

  • 1.拷贝的概念
  • 2.浅拷贝
    • 2.1. 浅拷贝的定义
    • 2.2. 浅拷贝的实现方式
    • 2.3 在内存中:
  • 3. 深拷贝
    • 3.1. 深拷贝的定义
    • 3.2. 深拷贝的实现方式
    • 3.3 在内存中
  • 4. 深拷贝与浅拷贝的区别
  • 5. 原型模式与深浅拷贝的关系
  • 6. 总结

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

  • 浅拷贝和深拷贝是常见的拷贝方式,用于创建对象副本。
  • 浅拷贝只复制引用。
  • 深拷贝复制整个对象及其嵌套的对象和数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1025269.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

循环神经网络--01 序列模型

生成数据 import torch from torch import nn from d2l import torch as d2lT 1000 time torch.arange(1,T1,dtypetorch.float32) x torch.sin(0.01*time)torch.normal(0,0.2,(T,)) d2l.plot(time,x,time,xlim[1,1000],figsize(6,3))将序列转换为特征-标签对(fe…

【大数据之Kafka】十五、Kafka-Kraft模式

1 Kafka-Kraft架构 左图为 Kafka 现有架构,元数据在 zookeeper 中,运行时动态选举 controller,由controller 进行 Kafka 集群管理。   右图为 kraft 模式架构(实验性),不再依赖 zookeeper 集群&#xff0…

以服务方式启动安防监控系统EasyNVR程序出现播放异常,是什么原因?

EasyNVR安防视频监控平台的特点是基于RTSP/Onvif协议,将前端设备统一接入,在平台进行转码、直播、处理及分发,在智慧安防视频监控场景中,EasyNVR可实现实时监控、云端录像、检索与回放、云存储、告警、级联等视频能力,…

湖南株洲三维扫描检测CNC机加工零件截面检测弧度测量-CASAIM中科广电

自工业时代开始以来,机械加工及零部件产业已经涵盖了各大电器零部件、汽车零部件、建筑机械零部件、航空航天零部件、海洋工程零部件等领域,涉及多种机械机床及工具仪器的制造。 零件在加工过程中,受制于加工工艺等各方面的因素,…

Tomcat调优【精简版】

Tomcat调优 优化Tomcat内存分配 调整Tomcat启动脚本contalina.sh,设置tomcat启动时分配的内存很可使用的最大内存; CATALINA_OPTS 调整Tomcat线程池 Tomcat默认使用的线程池:ThreadPoolExecutor 可以通过修改server.xml的 Connector 节点下的 maxThreads、minSpareThread…

关于删除的一些小纰漏

前端ajax如果传参不正确,会报500的错,可能是路径文件夹名字不对,一定要确认好,大写与小写的区别:question/QuestionStem_deleteList.do?ids"ids, 还有后面要加get请求后面要加"id",然后后面要加入传的…

004:vue使用relation-graph实现关系图谱

文章目录 1. 效果2. relation-graph简介3. 安装及使用4. 其他更多示例 1. 效果 2. relation-graph简介 这是一个Vue关系图谱组件,可以展示如组织机构图谱、股权架构图谱、集团关系图谱等知识图谱,可提供多种图谱布局,包括树状布局、中心布局…

神经网络训练防止过拟合和欠拟合的方法

神经网络训练防止过拟合和欠拟合的方法 1 过拟合的概念2 欠拟合的概念3 防止过拟合和欠拟合的方法 1 过拟合的概念 如上图所示,模型在训练时表现较好,在验证或测试时,表现较差,即表示过拟合。 过拟合的本质是模型对训练样本过度学…

Linux CentOS7 wc命令

wc命令的功能为统计指定文件中的字节数、字数、行数, 并将统计结果显示输出。 录入 man wc 可以查看相关信息 基本语法: wc [选项] 文件… 说明:该命令统计给定文件中的字节数、字数、行数。如果没有给出文件名,则从标准输入读取。wc同时也…

Online Fast Adaptive Low-Rank Similarity Learning for Cross-Modal Retrieval部分复现

表1 我的结果: R50条件下的均值:0.52889 Rall条件下的均值:0.430458

Vue 学习笔记 错误ResizeObserver loop completed with undelivered notifications

环境Vue3 Ts 使用了el-table 后,容易出现如下错误 ERROR ResizeObserver loop completed with undelivered notifications. at handleError (webpack-internal:///./node_modules/webpack-dev-server/client/overlay.js:299:58) at eval (webpack-internal:///./nod…

pytorch代码实现之动态卷积模块ODConv

ODConv动态卷积模块 ODConv可以视作CondConv的延续,将CondConv中一个维度上的动态特性进行了扩展,同时了考虑了空域、输入通道、输出通道等维度上的动态性,故称之为全维度动态卷积。ODConv通过并行策略采用多维注意力机制沿核空间的四个维度…

全局异常处理器@RestControllerAdvice解析 Springboot项目异常处理 JavaWeb @ExceptionHandler

RestControllerAdvice public class GlobalExceptionHandler {ExceptionHandler(Exception.class)//指定捕获异常类型:所有public Result ex(Exception ex){ex.printStackTrace();return Result.error("对不起,出现异常,请联系管理员");}}RestControllerAdvice注解在…

基于Yolov8的野外烟雾检测(1)

目录 1.Yolov8介绍 2.野外火灾烟雾数据集介绍 2.1数据集划分 1.2 通过voc_label.py得到适合yolov8需要的txt 2.3生成内容如下 3.训练结果分析 4.系列篇 1.Yolov8介绍 Ultralytics YOLOv8是Ultralytics公司开发的YOLO目标检测和图像分割模型的最新版本。YOLOv8是一种尖端的…

1千听歌猜歌名疯狂猜歌ACCESS\EXCEL数据库

就是从今年开始,各类的“猜”游戏开始火爆,先是猜图,比如看图猜明星、看图猜成语、看图猜电影、看图猜电视剧、看图猜背景、看图猜游戏、看图猜影视人物、看图猜景点等。然后又开始猜音频,猜音频最多的是歌。甚至现在的《一站到底…

每日一题:请解释什么是闭包(Closure)?并举一个实际的例子来说明。(前端初级)

今天继续在前端初级笔试题中被AI虐: 碱面的答案,问题:初级,回答:初级https://bs.rongapi.cn/1702510598371151872/14我的回答如下: 闭包是指由大括号包裹的一个区域,这个区域代表了一个变量生效…

【数据分享】我国六普的乡镇(街道)人口数据(免费获取)

人口数据是我们在各项研究中都经常使用的数据!人口数据的主要来源是人口普查,全国性的人口普查每十年进行一次。最近三次的人口普查分别是:2000年的第五次全国人口普查,简称五普;2010年的第六次全国人口普查&#xff0…

海外网红营销安全指南:品牌必须遵守的10大法律法规

随着互联网的普及和社交媒体的崛起,品牌们越来越倾向于与海外网红合作,以扩大其在全球市场的影响力。然而,这一战略并非没有风险,因为在不同国家和地区,存在着各种各样的法律法规,可能会影响品牌与海外网红…

JavaScript小案例-tab栏切换(可移除item)

gif效果图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>tab栏切…

使用JQ获取并渲染三级联动分类数据

数据JSON格式 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </he…