.NET基础知识之八——深拷贝,浅拷贝
目录
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基础知识之八——深拷贝,浅拷贝的更多相关文章
- Java基础 深拷贝浅拷贝
Java基础 深拷贝浅拷贝 非基本数据类型 需要new新空间 class Student implements Cloneable{ private int id; private String na ...
- Python开发【第二篇】:Python基础知识
Python基础知识 一.初识基本数据类型 类型: int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1,即-2147483648-2147483647 在64位 ...
- 浅析C++基础知识
近期想对C++的面试题目进行一下更加详细的整理.事实上认真思考一下C++程序猿的面试,我们能够发现对程序猿的能力的考察总是万变不离当中,这些基础知识主要分为五部分:一. C/C++基础知识 二. C/ ...
- JVM菜鸟进阶高手之路十(基础知识开场白)
转载请注明原创出处,谢谢! 最近没有什么实战,准备把JVM知识梳理一遍,先以开发人员的交流来谈谈jvm这块的知识以及重要性,依稀记得2.3年前用solr的时候老是经常oom,提到oom大家应该都不陌生 ...
- 面试基础知识集合(python、计算机网络、操作系统、数据结构、数据库等杂记)
python python _.__.__xx__之间的差别 python中range.xrange和randrange的区别 python中 =.copy.deepcopy的差别 python 继承 ...
- C++之基础知识20170830
/*************************************************************************************************** ...
- 【前端】之JavaScript基础知识
JS 基础知识 JS中,简单类型的数据存储在栈中,复杂类型的数据存储在堆中,其引用存储在栈中 JS中的深拷贝和浅拷贝: 浅拷贝:将对象中的所有简单类型的属性拷贝出来,引用类型属性直接赋值null 深拷 ...
- python基础知识的学习和理解
参考链接:https://github.com/yanhualei/about_python/tree/master/python_learning/python_base python基础知识笔 ...
- 「Java面试题/知识点精华集」20000+字的Java基础知识篇(2020最新版) !
本文已经收录进我的 79K Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java学习+面试指南」一份涵盖大 ...
随机推荐
- POJ-1080 Human Gene Functions---类似LCS
题目链接: https://cn.vjudge.net/problem/POJ-1080 题目大意: 给定两组序列,要你求出它们的最大相似度,每个字母与其他字母或自身和空格对应都有一个打分,求在这两个 ...
- W5100与MCU的连接方式
W5100与MCU的连接方式 W5100与MCU的连接方式主要有直接总线连接.间接总线连接.SPI总线连接这三种连接方法,不同的连接方法适应于不同的场合,应该按需选择最恰当的连接方式. 1)直接总线连 ...
- Doubly Linked List
Doubly Linked List Your task is to implement a double linked list. Write a program which performs th ...
- JavaScript面向对象编程之创建对象
参考资料依旧<JavaScript高级程序设计>,不得不说这本书写的太好了,讲的极为清晰凝练,好书! 先给出重点笔记,好好理解下面的三条笔记,每一句话都很重要: 1.实例的指针仅指向原型, ...
- Storm 中drpc调用
package storm.starter; import backtype.storm.Config; import backtype.storm.LocalCluster; import back ...
- SqlSugar之DbContext
创建一个DbContext和DbSet进行使用,我们可以在DbSet中进行扩展我们的方法 //可以直接用SimpleClient也可以扩展一个自个的类 //推荐直接用 SimpleClient //为 ...
- triplet loss
因为待遇低,因为工作不开心,已经严重影响了自己的工作积极性和工作效率,这几天发觉这样对自己实在是一种损失,决定提高工作效率,减少工作时间. 说说最近做的tracking, multi-object t ...
- android(eclipse)广播机制知识梳理(三)
1:分类: 标准广播:没有先后顺序,无法被截断 有序广播:又先后顺序,可以截断 2:接收广播:首先进行注册,注册的方式有静态注册和动态注册.也就是在代码中注册和在AndroidManifest ...
- vue项目模拟后台数据
这次我们来模拟一些后台数据,然后去请求它并且将其渲染到界面上.关于项目的搭建鄙人斗胆向大家推荐我的一篇随笔<Vue开发环境搭建及热更新> 一.数据建立 我这里为了演示这个过程所以自己编写了 ...
- [Windows]ping itsafe&环境变量
(1)when you ping a computer from itsafe,the ping command should return the local IP address. (2)wind ...