淺談.net平臺(tái)下深拷貝和淺拷貝
基本概念:
淺拷貝:指對(duì)象的字段被拷貝,而字段引用的對(duì)象不會(huì)被拷貝,拷貝對(duì)象和原對(duì)象僅僅是引用名稱有所不同,但是它們共用一份實(shí)體。對(duì)任何一個(gè)對(duì)象的改變,都會(huì)影響到另外一個(gè)對(duì)象。大部分的引用類型,實(shí)現(xiàn)的都是淺拷貝,引用類型對(duì)象之間的賦值,就是復(fù)制一個(gè)對(duì)象引用地址的副本,而指向的對(duì)象實(shí)例仍然是同一個(gè)。
深拷貝:指對(duì)象的子段被拷貝,同時(shí)字段引用的對(duì)象也進(jìn)行了拷貝。深拷貝創(chuàng)建的是整個(gè)源對(duì)象的結(jié)構(gòu),拷貝對(duì)象和原對(duì)象相互獨(dú)立,不共享任何實(shí)例數(shù)據(jù),修改一個(gè)對(duì)象不會(huì)影響到另一個(gè)對(duì)象。值類型之間的賦值操作,執(zhí)行的就是深拷貝。
基本概念之參考代碼:
class Program
{
static void Main(string[] args)
{
Student s1 = new Student("li", 23);
//淺拷貝
Student s2 = s1;
s2.Age = 27;
s1.ShowInfo();//li's age is 27
//深拷貝
int i = 12;
int j = i;
j = 22;
Console.WriteLine(i);//12
Console.Read();
}
}
class Student
{
public string Name;
public int Age;
public Student(string name, int age)
{
Name = name;
Age = age;
}
public void ShowInfo()
{
Console.WriteLine("{0}'s age is {1}", Name, Age);
}
}
分析:
在上例中,實(shí)例s2對(duì)s1進(jìn)行了淺拷貝,對(duì)s2中的Age字段進(jìn)行更改,繼而影響實(shí)例s1中的Age字段。
深拷貝中,僅僅是值類型間簡(jiǎn)單的賦值,對(duì)“j”做出的更改不會(huì)更改“i”的值。
深淺拷貝的實(shí)現(xiàn):
public object Clone()
{
return this.MemberwiseClone();
}
MemberwiseClone:創(chuàng)建一個(gè)淺表副本。過程是創(chuàng)建一個(gè)新對(duì)象,然后將當(dāng)前對(duì)象的非靜態(tài)字段復(fù)制到該新對(duì)象。如果字段是值類型,則對(duì)該字段執(zhí)行逐位復(fù)制,如果字段是引用類型,則復(fù)制引用但不復(fù)制引用對(duì)象。
參考代碼:
class Program
{
static void Main(string[] args)
{
ClassA ca = new ClassA();
ca.value = 88;
ClassA ca2 = new ClassA();
ca2 = (ClassA)ca.Clone();
ca2.value = 99;
Console.WriteLine(ca.value + "-----" + ca2.value);//88---99
ClassB cb = new ClassB();
cb.Member.value = 13;
ClassB cb2 = (ClassB)cb.Clone();
cb2.Member.value = 7;
Console.WriteLine(cb.Member.value.ToString() + "------" + cb2.Member.value.ToString());//淺拷貝:7---7 深拷貝:13----7
Console.Read();
}
}
public class ClassA : ICloneable
{
public int value = 0;
public object Clone()
{
return this.MemberwiseClone();
}
}
public class ClassB : ICloneable
{
public ClassA Member = new ClassA();
public object Clone()
{
//淺拷貝
return this.MemberwiseClone();
//深拷貝
ClassB obj = new ClassB();
obj.Member = (ClassA)Member.Clone();
return obj;
}
}
分析:
上例中,ca2復(fù)制ca對(duì)象,實(shí)現(xiàn)了深度拷貝。結(jié)果如同代碼中顯示:ca2中值類型字段的改變并不影響ca中的字段。
在類ClassB中,引用類型成員Member,如果用ClassA中的clone方法實(shí)現(xiàn)則僅僅實(shí)現(xiàn)的是淺拷貝,在上述參考代碼中能夠看出:對(duì)cb2的member的改變影響著cb。但是當(dāng)使用參考代碼中的深度拷貝后,對(duì)cb2的member的改變則不會(huì)影響著cb。
在網(wǎng)上找到一個(gè)綜合的例子,有對(duì)比的來進(jìn)行解釋深淺拷貝:
實(shí)例1:
public class Sex:ICloneable
{
private string _PSex;
public string PSex
{
set{ _PSex = value;}
get { return _PSex; }
}
//public object Clone()
//{
// return this.MemberwiseClone();
//}
}
public class Person : ICloneable
{
private Sex sex = new Sex();
public int aa = 3;
public string pSex
{
set { sex.PSex = value; }
get { return sex.PSex; }
}
private string _PName;
public string PName
{
set { this._PName = value; }
get { return this._PName; }
}
public void ShowPersonInfo()
{
Console.WriteLine("-------------------------");
Console.WriteLine("Name:{0} Sex:{1}", _PName, this.pSex);
Console.WriteLine("-------------------------");
Console.WriteLine(this.aa);
}
//淺拷貝
public object Clone()
{
return this.MemberwiseClone();
}
//深拷貝
public object DeepClone()
{
Person newP = new Person();
newP.PName = this._PName;
newP.pSex = this.pSex;
return newP;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("原對(duì)象:");
Person p = new Person();
p.PName = "Lee";
p.pSex = "男";
p.ShowPersonInfo();//原對(duì)象:lee 男 3
//淺拷貝
Person copy = (Person)p.Clone();
//深拷貝
Person dcopy = (Person)p.DeepClone();
Console.WriteLine("修改后的原對(duì)象:");
p.PName = "Zhao";
p.pSex = "女";
p.aa = 1;
p.ShowPersonInfo();//zhao 女 1
Console.WriteLine("修改后的淺拷貝對(duì)象:");
copy.ShowPersonInfo();//lee 女 3
Console.WriteLine("修改后的深拷貝對(duì)象:");
dcopy.ShowPersonInfo();//lee 男 3
Console.WriteLine("直接拷貝對(duì)象:");
Person PP = p;
PP.ShowPersonInfo();//zhao 女 1
Console.ReadLine();
}
}
分析:
首先需指出,上例中在類Sex中,加入Clone方法和不加對(duì)實(shí)例中運(yùn)算結(jié)果沒有影響。
類Person中,引用類型但卻是string類型的PName字段,引用類型pSex字段,值類型aa。
初始值:lee 男 3 (先進(jìn)行深淺拷貝)
修改值:zhao 女 1
淺拷貝值:lee 女 3
深拷貝值:lee 男 3
直接拷貝值:趙 女 1
結(jié)果:上述可以說是對(duì)深淺拷貝中經(jīng)常遇到的幾種類型做出總結(jié)和對(duì)比,相信在一番體悟后可以學(xué)到一些知識(shí)。
實(shí)例2:
class Program
{
static void Main(string[] args)
{
int[] numbers = { 2, 3, 4, 5 };
int[] numbersCopy = new int[5];
numbers.CopyTo(numbersCopy, 0);
numbersCopy[2] = 0;
int[] numbers1 = { 2, 3, 4, 5 };
int[] numbersClone1 = (int[])numbers1.Clone();
numbersClone1[2] = 0;
Console.Write(numbers[2] + "---" + numbersCopy[2]);//4---0
Console.Write(numbers1[2] + "---" + numbersClone1[2]);//4--0
//數(shù)組的復(fù)制也就是引用傳遞,指向的是同一個(gè)地址
int[] numbers2 = { 2, 3, 4, 5 };
int[] numbers2Copy = numbers2;
numbers2Copy[2] = 0;
Console.Write(numbers2[2]);//0
Console.Write(numbers2Copy[2]);//0
Console.Read();
}
}
暫不做分析,認(rèn)真領(lǐng)悟。
相關(guān)文章
asp.net中實(shí)體類對(duì)象賦值到表單的實(shí)現(xiàn)代碼
昨天在網(wǎng)上看到了一個(gè)利用反射表單賦值到實(shí)體類對(duì)象的一個(gè)方法,自己就在加了個(gè)方法,從實(shí)體對(duì)象到表單,覺的很不錯(cuò)非常省事,所以把他寫成了一個(gè)類,供以后使用2010-11-11ASP.NET單選按鈕控件RadioButton常用屬性和方法介紹
RadioButton又稱單選按鈕,其在工具箱中的圖標(biāo)為 ,單選按鈕通常成組出現(xiàn),用于提供兩個(gè)或多個(gè)互斥選項(xiàng),即在一組單選鈕中只能選擇一個(gè)2014-04-04ASP.Net頁(yè)尾中添加JavaScript的最佳方法實(shí)戰(zhàn)分享
將JavaScript腳本或庫(kù)添加到asp.net頁(yè)的末尾方法有很多,究竟哪一個(gè)最好使呢有利于日后的維護(hù)啊,是個(gè)疑點(diǎn)啊,本文的出現(xiàn)將幫你解決所有的困惑,感興趣的你可不要錯(cuò)過了哈2013-02-02ASP.NET MVC使用EPPlus,導(dǎo)出數(shù)據(jù)到Excel中
這篇文章介紹的是怎樣導(dǎo)出數(shù)據(jù)到Excel文件中,大多數(shù)的后端程序都有報(bào)表功能:把顯示在Grid中的數(shù)據(jù)導(dǎo)出到Excel文件中,這篇文章中使用的是EPPlus組件。需要的朋友可以參考借鑒2016-12-12.net MVC 連接數(shù)據(jù)本地?cái)?shù)據(jù)庫(kù)三種方法總結(jié)
這篇文章主要介紹了.net MVC 連接數(shù)據(jù)本地?cái)?shù)據(jù)庫(kù)三種方法總結(jié)的相關(guān)資料,這里附有代碼實(shí)例,需要的朋友可以參考下2016-12-12NET頁(yè)面導(dǎo)出Excel實(shí)例代碼
這篇文章主要介紹了NET頁(yè)面導(dǎo)出Excel的實(shí)例代碼,大家參考用2013-11-11