深复制VS浅复制

简介: 深复制VS浅复制

一、前言  


在C#中呢我们经常会看到或者听到这样的专业术语——深复制和浅复制,当然我也是在学习的过程中遇到了这两个概念,我就在这浅显的解析一下:

很多人对于这两个概念有这样不完全的理解:浅复制对于引用类型拷贝地址,对于值类型直接拷贝


二、概念对比


对象的拷贝也就是从现有对象复制一个“一模一样”的新对象出来。虽然都是复制对象,但是不同的复制方法,复制出来的新对象却并非完全一模一样,对象内部存在着一些差异。通常的复制方法有两种,即深拷贝和浅拷贝,那二者之间有何区别呢?MSDN里对 IClone接口的Clone方法有这样的说明:在深层副本中,所有的对象都是重复的;而在浅表副本中,只有顶级对象是重复的,并且顶级以下的对象包含引用。可以看出,深复制和浅复制之间的区别在于是否复制了子对象。这如何理解呢?下面我通过带有子对象的代码来验证二者的区别。


提示:在下面的代码中ICloneable 接口是在System命名空间中提供的,其中已只有一个唯一的一个方法 Clone();


三、实例


浅复制部分


20141114165403045.jpg

<span style="font-size:24px;"> class WorkExperience
        {
            private string workDate;
            public string WorkDate              //定义一个属性
            {
                get { return workDate; }
                set { workDate = value; }
            }
            private string company;
            public string Company
            {
                get { return company; }
                set { company = value; }
            }
        }
        //简历类
        class Resume : ICloneable
        {
            private string name;
            private string sex;
            private string age;
            private WorkExperience work;    //引用工作经历对象
            public Resume(string name)      //构造函数 并且在类实例化是同时实例化工作经历
            {
                this.name = name;
                work = new WorkExperience();
            }
            //设置个人信息
            public void SetPersonalInfo(string sex, string age)
            {
                this.sex = sex;
                this.age = age;
            }
            //设置工作经历
            public void SetWorkExperience(string workDate, string company)
            {
                work.WorkDate = workDate;
                work.Company = company;
            }
            //显示
            public void Display()
            {
                Console.WriteLine("{0} {1} {2}", name, sex, age);
                Console.WriteLine("{0} {1}", work.WorkDate, work.Company);
            }
            public object Clone()
            {
                return (object)this.MemberwiseClone();
            }
        }</span>
<span style="font-size:24px;">                Resume a = new Resume("大鸟");
                a.SetPersonalInfo("男", "29");
                a.SetWorkExperience("1998-2000", "xx公司");
                Resume b = (Resume)a.Clone();
                b.SetWorkExperience("1998-2006", "YY公司");
                Resume c = (Resume)a.Clone();
                c.SetPersonalInfo("男", "24");
                c.SetWorkExperience("1998-2003", "zz企业");
                a.Display();
                b.Display();
                c.Display();
                Console.Read();</span

运行结果是

20141114165717671.jpg


而我们希望达到的效果是这样的:


20141114211816074.jpg


这种差异就是我们在写代码的过程中没有注意到深复制和浅复制的区别,对于引用类型,就是复制了引用,对引用对象还是指向了原来的对象!


深复制部分


20141114213223405.jpg

        class WorkExperience : ICloneable  //让工作经历实现ICloneable接口
        {
            private string workDate;
            public string WorkDate              //定义一个属性
            {
                get { return workDate; }
                set { workDate = value; }
            }
            private string company;
            public string Company
            {
                get { return company; }
                set { company = value; }
            }
            public object Clone()   //工作经历类,实现克隆方法
            {
                return (object)this.MemberwiseClone();
            }
        }
        //简历类
        class Resume : ICloneable
        {
            private string name;
            private string sex;
            private string age;
            private WorkExperience work;    //引用工作经历对象
            public Resume(string name)      //构造函数 并且在类实例化是同时实例化工作经历
            {
                this.name = name;
                work = new WorkExperience();
            }
            //提供Clone 方法调用的私有构造函数,以便克隆工作经历 的数据
            private Resume(WorkExperience work)
            {
                this.work = (WorkExperience)work.Clone();
            }
            //设置个人信息
            public void SetPersonalInfo(string sex, string age)
            {
                this.sex = sex;
                this.age = age;
            }
            //设置工作经历
            public void SetWorkExperience(string workDate, string company)
            {
                work.WorkDate = workDate;
                work.Company = company;
            }
            //显示
            public void Display()
            {
                Console.WriteLine("{0} {1} {2}", name, sex, age);
                Console.WriteLine("{0} {1}", work.WorkDate, work.Company);
            }
            //调用私有的构造方法,让 工作经历 克隆完成,然后在给这个简历 对象的相关字段赋值
            //最终返回一个深赋值的简历对象
            public object Clone()
            {
                Resume obj = new Resume(this.work);
                obj.name = this.name;
                obj.sex = sex;
                obj.age = age;
                return obj;
            }
        }
            //深复制和浅复制的客户端代码相同
            Resume a = new Resume("大鸟");
            a.SetPersonalInfo("男", "29");
            a.SetWorkExperience("1998-2000", "xx公司");
            Resume b = (Resume)a.Clone();
            b.SetWorkExperience("1998-2006", "YY公司");
            Resume c = (Resume)a.Clone();
            c.SetPersonalInfo("男", "24");
            c.SetWorkExperience("1998-2003", "zz企业");
            a.Display();
            b.Display();
            c.Display();

在这段代码中我们实现了预期的效果!


我们在从两个比较简单的图来认识一下:


20141114214444234.jpg

20141114214512081.jpg


四、总结:


从以上结果可以看出,深拷贝时两个对象是完全“分离”的,改变其中一个,不会影响到另一个对象;浅拷贝时两个对象并未完全“分离”,改变顶级对象的内容,不会对另一个对象产生影响,但改变子对象的内容,则两个对象同时被改变。这种差异的产生,即是取决于拷贝子对象时复制内存还是复制指针。深拷贝为子对象重新分配了一段内存空间,并复制其中的内容;浅拷贝仅仅将指针指向原来的子对象。

目录
相关文章
|
运维 Prometheus 分布式计算
阿里云 ACK One 多集群管理全面升级:多集群服务、多集群监控、两地三中心应用容灾
本文介绍了 ACK One 近期发布的 3 个主要特性,覆盖了多集群管理的 3 个主要场景,跨集群服务发现与访问、多集群全局监控、应用容灾。除多集群管理外,ACK One 更是支持连接并管理任何地域、任何基础设施上的 Kubernetes 集群,提供一致的管理和社区兼容的 API,支持对计算、网络、存储、安全、监控、日志、作业、应用、流量等进行统一运维管控。
阿里云 ACK One 多集群管理全面升级:多集群服务、多集群监控、两地三中心应用容灾
|
3月前
|
运维 监控 Cloud Native
从本土到全球,云原生架构护航灵犀互娱游戏出海
本文内容整理自「 2025 中企出海大会·游戏与互娱出海分论坛」,灵犀互娱基础架构负责人朱晓靖的演讲内容,从技术层面分享云原生架构护航灵犀互娱游戏出海经验。
398 16
|
21天前
|
机器学习/深度学习 人工智能 算法
计算机的起源
从机械齿轮到量子计算,计算机的演进是一部人类智慧的史诗。本书讲述跨越五千年的计算文明史:从算盘到AI,从巴贝奇到图灵,揭示科技背后的逻辑与梦想,展现数字时代如何重塑世界。
|
26天前
|
人工智能 算法 搜索推荐
AI 搜索时代选 GEO 外援?十家服务商,企业看过来
随着AI普及,GEO(生成式引擎优化)成为品牌获客新赛道。本文推荐10家优质GEO服务商,涵盖内容优化、流量提升、合规风控等方向,助力企业提升在DeepSeek、豆包等AI模型中的曝光与推荐,实现智能时代的精准增长。
|
5月前
|
缓存 安全 Shell
《HarmonyOSNext未成年人守护盾:3分钟搞定全自动分龄保护开发指南》
《HarmonyOS Next未成年人守护盾:3分钟搞定全自动分龄保护开发指南》详解华为“未成年人模式”开发要点,涵盖适龄应用判断、系统接口调用、远程守护等功能,助力开发者快速实现合规的儿童上网保护功能。
515 0
|
机器学习/深度学习 人工智能 并行计算
【人工智能】CPU、GPU与TPU:人工智能领域的核心处理器概述
在人工智能和计算技术的快速发展中,CPU(中央处理器)、GPU(图形处理器)和TPU(张量处理器)作为核心处理器,各自扮演着不可或缺的角色。它们不仅在性能上各有千秋,还在不同的应用场景中发挥着重要作用
1008 2
|
8月前
|
存储 关系型数据库 分布式数据库
登顶TPC-C|云原生数据库PolarDB技术揭秘:单机性能优化篇
日前,阿里云PolarDB云原生数据库以超越原记录2.5倍的性能一举登顶TPC-C基准测试排行榜,以每分钟20.55亿笔交易(tpmC)和单位成本0.8元人民币(price/tpmC)的成绩刷新TPC-C性能和性价比双榜的世界纪录。 每一个看似简单的数字背后,都蕴含着无数技术人对数据库性能、性价比和稳定性的极致追求,PolarDB的创新步伐从未止步。「阿里云瑶池数据库」公众号特此推出「PolarDB登顶TPC-C技术揭秘」系列硬核文章,为你讲述“双榜第一”背后的故事,敬请关注!
登顶TPC-C|云原生数据库PolarDB技术揭秘:单机性能优化篇
|
数据库连接 API Apache
(二)Open Stack(M)----Keystone安装和配置(上)
(二)Open Stack(M)----Keystone安装和配置(上)
406 0
|
Prometheus 监控 Cloud Native
使用 Jenkins 监控和优化构建性能
【8月更文第31天】在软件开发的过程中,构建性能直接影响着开发效率和团队的生产力。一个快速、可靠的构建流程可以显著加快迭代速度,减少等待时间,使团队能够更快地响应变化。Jenkins 作为一款广泛使用的持续集成/持续交付(CI/CD)工具,提供了丰富的功能来帮助开发者监控和优化构建性能。本文将探讨如何利用 Jenkins 的内置工具和外部工具来监控构建性能,并提出一些具体的优化方案。
1103 0
|
IDE API 开发工具
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Scroll容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Scroll容器组件
1238 0