目录

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. Android(java)学习笔记48:通过反射获得带参构造方法并且使用

    1. 反射获得带参构造方法并且使用: (1)获取字节码文件对象       Class c = Class.forName("cn.itcast_01.Person"); (2)获 ...

  2. Android学习笔记_66_图片处理专题

    1.图片缩放:不解析整个图片信息. public class DemoActivity extends Activity { @Override public void onCreate(Bundle ...

  3. 【转载】Atom 是一款各方面体验都很像 Sublime Text 的编辑器

    转载:http://www.appinn.com/atom-editor/ Atom 是一款各方面体验都很像 Sublime Text 的编辑器,它由 Github 出品,目前免费. Atom 功能的 ...

  4. 【XP-IE8】XP系统的IE8无法正常访问图片,按钮无反应,不执行JS脚本代码

    环境: Windows XP ,自带的是IE6,另外安装的 IE8 . 状况: 使用IE8浏览内网网站,点击登录按钮,没有反应.滚动图片新闻不显示.但使用Chrome浏览器,一切正常,说明是IE8某处 ...

  5. ImportError: No module named lmdb

    why? 具体原因没有查清楚.安装caffe时,按照要求安装了包,caffe用的好好的,而且我也用打好包的lmdb跑了程序了.可我今天想看一下我的打包数据是不是漏掉数据了,直接开个python窗口,i ...

  6. linux网络相关配制及命令

    1.虚拟机配制 查看ip: ip addr 配制网卡(读者可以忽略): 编辑虚拟网络编辑器,修改子网IP 查看ip,输入ip addr 开启网络:ifup eth0  关闭网络:ifdown eth0 ...

  7. repo配置与连接

    repo是远程访问android源码的工具,和git一起使用. repo的远程安装经常被屏蔽,你懂得. sudo apt-get  install  curl  244  sudo apt-get - ...

  8. JavaScript 基础(四) 循环

    JavaScript的循环有两种,一种是for 循环,通过初始条件,结束条件和递增条件来循环执行语句块: var x = 0; var i; for(i=1; i <=10000; i++){ ...

  9. MySQL 字符串函数:字符串截取

    1.left(name,4)截取左边的4个字符 列: ,) 年 结果:2018 2.right(name,2)截取右边的2个字符 ,) 月份 结果:09 3.SUBSTRING(name,5,3) 截 ...

  10. CDN初识

    CDN 全称:Content Delivery Network或Content Ddistribute Network,即内容分发网络,通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层 ...