目录

1、概念

2、使用赋值符号“=”

3、浅复制

4、深复制

5、问题一:如果类里面嵌套有多个类,然后嵌套类里面又嵌套类,那么像上面实现深拷贝的方法还能用吗?

6、问题二:实现深拷贝时,一定要实现ICloneable接口吗?

1、概念:

         浅拷贝是将一个对象里面的所有字段重新拷贝一个到另外一个对象中去,如果字段是值类型,那么它拷贝的就是值,如果字段类型是引用类型,那么它拷贝的就是地址;

        深拷贝是将一个对象里面的所有字段重新拷贝到另外一个对象中去,它与浅拷贝的区别是,如果字段是引用类型,它拷贝的不是地址,它会把引用类型里面每一个值重新拷贝一份,那就是说完全重新拷贝一个,新对象中的值不管怎么改变都不会影响以前的对象值。

         我们平时所知道的赋值符号“=”,如果是值类型,它就是拷贝值类型,如果是引用类型,它就是赋予的地址。

         由上面可以看出,“=”,浅拷贝,深拷贝对于值类型来说是没有区别的。针对引用类型来说是有区别的,看下面的例子。

         先定义一个People类,在People类里面有一个Address类,先看Address类:

   1: [Serializable]

   2: public class Address

   3: {

   4:     private string addressStr;

   5:  

   6:     public string AddressStr

   7:     {

   8:         get { return addressStr; }

   9:         set { addressStr = value; }

  10:     }

  11:  

  12:     private string addressNo;

  13:  

  14:     public string AddressNo

  15:     {

  16:         get { return addressNo; }

  17:         set { addressNo = value; }

  18:     }

  19:  

  20:     public override string ToString()

  21:     {

  22:         return AddressStr + ";" + AddressNo;

  23:     }

  24: }

          再来看People类:

   1: [Serializable]

   2: public class People:ICloneable

   3: {

   4:     private string strName;

   5:  

   6:     public string StrName

   7:     {

   8:         get { return strName; }

   9:         set { strName = value; }

  10:     }

  11:  

  12:     private int strNo;

  13:  

  14:     public int StrNo

  15:     {

  16:         get { return strNo; }

  17:         set { strNo = value; }

  18:     }

  19:  

  20:     private Address addStr;

  21:  

  22:     public Address AddStr

  23:     {

  24:         get

  25:         {

  26:             if (addStr == null)

  27:             {

  28:                 addStr = new Address();

  29:             }

  30:             return addStr;

  31:         }

  32:         set { addStr = value; }

  33:     }

  34:  

  35:     public override string ToString()

  36:     {

  37:         return StrName + ";" + strNo + addStr.ToString();

  38:     }

  39: }

         下面分三种情况来分析:

2、使用赋值符号“=”

         赋值符号,只是把引用类型的地址赋给了另外一个对象,对这个对象里面的任何修改都会对原对象产生影响。

   1: static void Main(string[] args)

   2: {

   3:     People people = new People()

   4:     {

   5:         StrName = "张三",

   6:         StrNo = 1,

   7:         AddStr = new Address { AddressNo = "10010", AddressStr = "北京市海淀区" }

   8:     };

   9:  

  10:     //使用等于号"="赋值的情况

  11:     People peopleZhang = new People();

  12:     peopleZhang = people;

  13:     Console.WriteLine("情况1(使用等于号' = '赋值的情况)原始值是:" + peopleZhang.ToString());

  14:     peopleZhang.StrNo = 2;

  15:     peopleZhang.AddStr.AddressNo = "432000";

  16:     Console.WriteLine("情况1(使用等于号' = '赋值的情况)修改后peopleZhang的值是:" + people.ToString());

  17:     Console.WriteLine("情况1(使用等于号' = '赋值的情况)修改后people的值是:" + people.ToString());

  18:     Console.ReadLine();

         输出结果如下:

3、浅复制

          浅复制是把对象的每个字段拷贝了一份给另外一个对象,如果这个引用对象里面有值类型,那么拷贝的是值类型的副本,如果是引用类型那么拷贝的是对象的地址。也就是说拷贝后的对象,如果修改对象里面的值类型不会对原对象的值类型的值有影响,但是如果修改对象里面引用类型的值,那么原有对象引用类型的值也会跟着改变。

          在People里面实现浅拷贝,可以自己实现,.NET里面也提供了一个方法MemberwiseClone,这个方法默认就是返回当前对象的副本,所以浅拷贝可以这样实现:

   1: public People ShallowCopy()

   2: {

   3:     return (People)this.MemberwiseClone();

   4: }

         前台调用如下:

   1: //使用浅克隆的情况

   2: People peopleWang = new People();

   3: peopleWang = people.ShallowCopy();

   4: Console.WriteLine("情况2(使用浅克隆的情况)原始值是:" + peopleWang.ToString());

   5: peopleWang.StrNo = 3;

   6: peopleWang.AddStr.AddressNo = "1234567";

   7: Console.WriteLine("情况2(使用浅克隆的情况)修改后peopleWang的值是:" + peopleWang.ToString());

   8: Console.WriteLine("情况2(使用浅克隆的情况)修改后people的值是:" + people.ToString());

   9: Console.ReadLine();

        输出结果如下:

4、深复制

          深复制是把对象的每个字段拷贝了一份给另外一个对象,如果这个引用对象里面有值类型,那么拷贝的是值类型的副本,如果是引用类型那么拷贝的不是对象的地址,而是把具体的值也拷贝一遍。也就是说拷贝后的对象,如果修改对象里面的值类型不会对原对象的值类型的值有影响,修改对象里面引用类型的值,也不会对原有对象引用类型的值有影响。

          实现深拷贝一般是实现ICloneable接口,具体实现方法如下:

   1: public Object Clone()

   2: {

   3:     People p = new People();

   4:     p.StrName = this.strName;

   5:     p.StrNo = this.strNo;

   6:     p.AddStr.AddressNo = this.addStr.AddressNo;

   7:     p.AddStr.AddressStr = this.addStr.AddressStr;

   8:  

   9:     return p;

  10: }

           前台调用如下:

   1: //使用深克隆的情况

   2: People peopleLi = new People();

   3: peopleLi = (People)people.Clone();

   4: //peopleLi = people.DeepClone();

   5: //peopleLi = people.DeepCloneBySerialize();

   6: Console.WriteLine("情况3(使用深克隆的情况)原始值是:" + peopleLi.ToString());

   7: peopleLi.StrNo = 4;

   8: peopleLi.AddStr.AddressNo = "8888888";

   9: Console.WriteLine("情况3(使用深克隆的情况)修改后peopleLi的值是:" + peopleLi.ToString());

  10: Console.WriteLine("情况3(使用深克隆的情况)修改后people的值是:" + people.ToString());

  11: Console.ReadLine();

           输出结果是:

          通过上面的实现代码,有下面两个问题:

5、问题一:如果类里面嵌套有多个类,然后嵌套类里面又嵌套类,那么像上面实现深拷贝的方法还能用吗?

           解决办法:可以通过序列化的形式来实现深拷贝,这样不管嵌套多少对象,我们不用关注具体的实现,只需要序列化后再反序列化就行了。代码如下:

   1: public People DeepCloneBySerialize()

   2: {

   3:     //调用此方法,必须把类标记为可序列化的,嵌套类也需要标记为可序列化的

   4:     using (Stream objectStream = new MemoryStream())

   5:     {

   6:         IFormatter formatter = new BinaryFormatter();

   7:         formatter.Serialize(objectStream, this);

   8:         objectStream.Seek(0, SeekOrigin.Begin);

   9:         return formatter.Deserialize(objectStream) as People;

  10:     }

  11: }

6、问题二:实现深拷贝时,一定要实现ICloneable接口吗?

           答案:不一定,ICloneable接口是微软提供的一个对象复制的接口,但是它并没有规定是深拷贝还是浅拷贝,由用户自己来决定实现哪一种的拷贝。也可以完全写一个方法实现深拷贝,不用实现这个接口。如下面的代码:

   1: public People DeepClone()

   2: {

   3:     People p = new People();

   4:     p.StrName = this.strName;

   5:     p.StrNo = this.strNo;

   6:     p.AddStr.AddressNo = this.addStr.AddressNo;

   7:     p.AddStr.AddressStr = this.addStr.AddressStr;

   8:  

   9:     return p;

  10: }

           这样就觉得ICloneable接口没有啥作用,而且还有一点不好的就是,如果父类实现了ICloneable接口,那么子类就必须要实现这个接口,因为如果子类不实现这个接口,那么调用子类的这个方法时,它就会去调用父类的这个方法,而父类的这个方法返回的是对父类这个对象 的拷贝,跟子类对象不是一个概念,所以就会有问题。

 

参考资料:

http://www.cnblogs.com/luminji/archive/2011/02/02/1948826.html

.NET基础知识之八——深拷贝,浅拷贝的更多相关文章

  1. Java基础 深拷贝浅拷贝

    Java基础 深拷贝浅拷贝 非基本数据类型 需要new新空间 class Student implements Cloneable{ private int id; private String na ...

  2. Python开发【第二篇】:Python基础知识

    Python基础知识 一.初识基本数据类型 类型: int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1,即-2147483648-2147483647 在64位 ...

  3. 浅析C++基础知识

    近期想对C++的面试题目进行一下更加详细的整理.事实上认真思考一下C++程序猿的面试,我们能够发现对程序猿的能力的考察总是万变不离当中,这些基础知识主要分为五部分:一. C/C++基础知识 二. C/ ...

  4. JVM菜鸟进阶高手之路十(基础知识开场白)

    转载请注明原创出处,谢谢! 最近没有什么实战,准备把JVM知识梳理一遍,先以开发人员的交流来谈谈jvm这块的知识以及重要性,依稀记得2.3年前用solr的时候老是经常oom,提到oom大家应该都不陌生 ...

  5. 面试基础知识集合(python、计算机网络、操作系统、数据结构、数据库等杂记)

    python python _.__.__xx__之间的差别 python中range.xrange和randrange的区别 python中 =.copy.deepcopy的差别 python 继承 ...

  6. C++之基础知识20170830

    /*************************************************************************************************** ...

  7. 【前端】之JavaScript基础知识

    JS 基础知识 JS中,简单类型的数据存储在栈中,复杂类型的数据存储在堆中,其引用存储在栈中 JS中的深拷贝和浅拷贝: 浅拷贝:将对象中的所有简单类型的属性拷贝出来,引用类型属性直接赋值null 深拷 ...

  8. python基础知识的学习和理解

    参考链接:https://github.com/yanhualei/about_python/tree/master/python_learning/python_base   python基础知识笔 ...

  9. 「Java面试题/知识点精华集」20000+字的Java基础知识篇(2020最新版) !

    本文已经收录进我的 79K Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java学习+面试指南」一份涵盖大 ...

随机推荐

  1. 记一次msfconsole_android渗透实验

    1>查看本机IP 2>生成App木马 3>将生成的木马安装至手机 4>打开msfconsole 1,  use exploit/multi/handler  加载模块. 2, ...

  2. webstorm识别php代码

    在 setting --editor--filetype---找到html 在下面的框里点右边加好,添加*.php

  3. Vue状态管理-Bus

    1.父子组件之间进行通讯: 父组件通过属性和子组件通讯,子组件通过事件和父组件通讯.vue2.x只允许单向数据传递. 先定义一个子组件AInput.vue: <template> < ...

  4. SpringMVC学习记录一——入门介绍和入门程序

    1       springmvc框架 1.1      什么是springmvc springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合. spr ...

  5. 【luogu P2764 最小路径覆盖问题】 模板

    题目链接:https://www.luogu.org/problemnew/show/P2764 把每个点在左边建一遍右边建一遍,再加上源点汇点,跑最大流,n-最大流就是答案. #include &l ...

  6. lucene&solr学习——分词器

    下图是语汇单元的生成过程: 从一个Reader字符流开始,创建基于Reader的Tokenizer分词器,经过三个TokenFilter生成语汇单元Tokens. 要看分词器的分析效果,只需要看Tok ...

  7. ATK 设计框架 之 Atk.CustomExpression

    在ATK-DataPortal框架中的xxxHandel中常用到的一种类型,形如: 1.protected virtual D ItemHandle(D item, Func<E, E> ...

  8. 大数据开发从入门小白到删库跑路(一)- 获取Hadoop

    Hadoop是一个可以通过相对简单编程模型实现跨多台计算机集群分布式处理大型数据集的框架.它不是依赖于高额成本的硬件可靠性来提供高可用性,Hadoop的设计能从单个服务器扩展到数千台机器,每个机器提供 ...

  9. 分别使用原生js和jQuery添加/删除元素的class属性

    一.原生js添加/删除元素的class属性: <!-- span元素原有class = "test" --> <span class="test&quo ...

  10. web3.js_1.x.x--API(一)event/Constant/deploy/options

    /* 事件是使用EVM日志内置功能的方便工具,在DAPP的接口中,它可以反过来调用Javascript的监听事件的回调. 事件在合约中可被继承.当被调用时,会触发参数存储到交易的日志中(一种区块链上的 ...