- 1、深拷貝和淺拷貝的區別?
- 2、求助深拷貝和淺拷貝的問題
- 3、深拷貝與淺拷貝的實現(一)
- 4、深淺複製/拷貝-什麼情況下用retain和copy
- 5、徹底講明白淺拷貝與深拷貝
- 6、深拷貝和淺拷貝怎樣理解(通俗具體點兒)大神們幫幫忙
1、淺拷貝可以使用列表自帶的copy()函數(如list.copy()),或者使用copy模塊的copy()函數。深拷貝只能使用copy模塊的deepcopy(),所以使用前要導入:from copy import deepcopy。
2、 如果拷貝的對象里的元素只有值,沒有引用,那淺拷貝和深拷貝沒有差別,都會將原有對象複製一份,產生一個新對象,對新對象里的值進行修改不會影響原有對象,新對象和原對象完全分離開。
3、 如果拷貝的對象里的元素包含引用(像一個列表裡儲存着另一個列表,存的就是另一個列表的引用),那淺拷貝和深拷貝是不同的,淺拷貝雖然將原有對象複製一份。
但是依然保存的是引用,所以對新對象里的引用里的值進行修改,依然會改變原對象里的列表的值,新對象和原對象完全分離開並沒有完全分離開。而深拷貝則不同,它會將原對象里的引用也新創建一個,即新建一個列表,然後放的是新列表的引用,這樣就可以將新對象和原對象完全分離開。
淺拷貝就比如像引用類型,而深拷貝就比如值類型。
淺拷貝是指源對象與拷貝對象共用一份實體,僅僅是引用的變量不同(名稱不同)。對其中任何一個對象的改動都會影響另外一個對象。舉個例子,一個人一開始叫張三,後來改名叫李四了,可是還是同一個人,不管是張三缺胳膊少腿還是李四缺胳膊少腿,都是這個人倒霉。
深拷貝是指源對象與拷貝對象互相獨立,其中任何一個對象的改動都不會對另外一個對象造成影響。舉個例子,一個人名叫張三,後來用他克隆(假設法律允許)了另外一個人,叫李四,不管是張三缺胳膊少腿還是李四缺胳膊少腿都不會影響另外一個人。比較典型的就是Value(值)對象,如預定義類型Int32,Double,以及結構(struct),枚舉(Enum)等。
C#中有兩種類型變量,一種 是值類型變量,一種是引用類型變量。對於前者,copy是屬於全盤複製;而對於後者,一般的copy只是淺copy,相當於只傳遞一個引用指針一樣。因此 對於後者進行真正copy的時候,也是最費事的,具體的說,必須為其實現ICloneable接口中提供的Clone方法。
淺拷貝(影子克隆):只複製對象的基本類型,對象類型,仍屬於原來的引用.
深拷貝(深度克隆):不緊複製對象的基本類,同時也複製原對象中的對象.就是說完全是新對象產生的.
淺 拷貝和深拷貝之間的區別:淺拷貝是指將對象中的數值類型的字段拷貝到新的對象中,而對象中的引用型字段則指複製它的一個引用到目標對象。如果改變目標對象 中引用型字段的值他將反映在原是對象中,也就是說原始對象中對應的字段也會發生變化。深拷貝與淺拷貝不同的是對於引用的處理,深拷貝將會在新對象中創建一 個新的和原是對象中對應字段相同(內容相同)的字段,也就是說這個引用和原是對象的引用是不同的,我們在改變新對象中的這個字段的時候是不會影響到原始對 象中對應字段的內容。所以對於原型模式也有不同的兩種處理方法:對象的淺拷貝和深拷貝。
MemberwiseClone 方法創建一個淺表副本,方法是創建一個新對象,然後將當前對象的非靜態字段複製到該新對象。如果字段是值類型的,則對該字段執行逐位複製。如果字段是引用 類型,則複製引用但不複製引用的對象;因此,原始對象及其複本引用同一對象。深拷貝,即實現ICloneable接口.ICloneable可用於深拷貝 和淺拷貝。
這些都是概念,但是需要我們理解,下面介紹實例:
using System;
using System.Collections.Generic;
using System.Text;
namespace WindowsApplication1
{
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;
}
}
public class class4
{
public static void Main()
{
ClassB sb = new ClassB();
sb.Member.Value = 15;
ClassB nb = (ClassB)sb.Clone();
nb.Member.Value = 6;
Console.Write(sb.Member.Value.ToString() + “—” + nb.Member.Value.ToString());
ClassA nnb = new ClassA();
nnb.Value = 111;
ClassA bbn = new ClassA();
bbn = (ClassA)nnb.Clone();
bbn.Value = 222;
Console.Write(bbn.Value);
Console.Read();
}
}
}
其中.MemberwiseClone()在上面已經介紹過了,通過實例可以清楚看到淺拷貝與深拷貝的區別
再來個:
using System;
using System.Collections.Generic;
using System.Text;
namespace WindowsApplication1
{
class Program
{
public class Sex
{
private string _PSex;
public string PSex
{
set
{
_PSex = value;
}
get
{
return _PSex;
}
}
}
public class Person : ICloneable
{
private Sex _pSex = new Sex();
public int aa = 1213;
public string pSex
{
set
{
_pSex.PSex = value;
}
get
{
return _pSex.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;
}
}
static void Main(string[] args)
{
Console.WriteLine(“原對象:”);
Person p = new Person();
p.PName = “JackLee”;
p.pSex = “男”;
p.ShowPersonInfo();
//淺拷貝
Person copy = (Person)p.Clone();
//深拷貝
Person dcopy = (Person)p.DeepClone();
Console.WriteLine(“修改後的原對象:”);
p.PName = “JackZhao”;
p.pSex = “女”;
p.aa = 1111;
p.ShowPersonInfo();
Console.WriteLine(“修改後的淺拷貝對象:”);
copy.ShowPersonInfo();
Console.WriteLine(“修改後的深拷貝對象:”);
dcopy.ShowPersonInfo();
Console.WriteLine(“直接拷貝對象:”);
Person PP = p;
PP.ShowPersonInfo();
Console.ReadLine();
}
}
}
接下來介紹一下數組的拷貝:
首先數組的直接拷貝也就是複製,不用多說看例子:
int [] numbers = { 2, 3, 4, 5};
int [] numbersCopy = numbers;
numbersCopy[2] = 0;
Console.Write(numbers[2]);
Console.Write(numbersCopy[2]);
結果就是
道理很簡單,數組的複製也就是引用傳遞,指向的是同一個地址,這不是我們介紹的重點
接下來
看一下概念
數組是引用類型,所以將一個數組變量賦予另一個數組變量,就會得到兩個指向同一數組的變量。而複製數組,會使數組實現ICloneable接口。這個接口定義的Clone()方法會創建數組的淺副本。
如果數組的元素是值類型,就會複製所有的值,如果數組包含引用類型,則不複製元素,而只複製引用,
除了使用Clone()方法之外,還可以使用Array.Copy()方法創建淺副本。但Clone()方法和Copy()方法有一個重要區別:Clone()方法會創建一個新數組,而Copy()方法只是傳送了階數相同、有足夠元素空間的已有數組。
提示:
如果需要包含引用類型的數組的深副本,就必須迭代數組,創建新對象。
看一下例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace WindowsApplication1
{
class Class2
{
public static void Main()
{
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]);
Console.Read();
}
}
}
我這裡介紹的主要是數組的clone和copyto的用法,兩者都不會改變其中的值,與上面我們的複製有很大的區別
最近的學習中,仔細研究了下深拷貝和淺拷貝,下面就來簡單的總結下。
首先我們了解下兩種 數據類型 :
1、基本類型:像Number、String、Boolean等這種為基本類型
2、複雜類型:Object和Array
接着我們分別來了解下淺拷貝和深拷貝,深拷貝和淺拷貝是只針對Object和Array這樣的複雜類型的。
淺拷貝 :
可以看出,對於對象或數組類型,當我們將a賦值給b,然後更改b中的屬性,a也會隨着變化。也就是說a和b指向了同一塊內存,所以修改其中任意的值,另一個值都會隨之變化,這就是淺拷貝。
深拷貝 :
剛剛我們了解了什麼是淺拷貝,那麼相應的,如果給b放到新的內存中,將a的各個屬性都複製到新內存里,就是深拷貝。
也就是說,當b中的屬性有變化的時候,a內的屬性不會發生變化。
那麼除了上面簡單的賦值引用,還有哪些方法使用了 淺拷貝 呢?
Object.assign()
在MDN上介紹Object.assign():”Object.assign() 方法用於將所有可枚舉的屬性的值從一個或多個源對象複製到目標對象。它將返回目標對象。”
複製一個對象
可以看到,Object.assign()拷貝的只是屬性值,假如源對象的屬性值是一個指向對象的引用,它也只拷貝那個引用值。所以Object.assign()只能用於淺拷貝或是合併對象。這是Object.assign()值得注意的地方。
那麼下面我們就來說說複雜的 深拷貝 。
jQuery.extend()
說到深拷貝,第一想到的就是jQuery.extend()方法,下面我們簡單看下jQuery.extend()的使用。
jQuery.extend( [deep ], target, object1 [, objectN ] ),其中deep為Boolean類型,如果是true,則進行深拷貝。
我們還是用上面的數據來看下extend()方法。
通過上面的對比可以看出,當使用extend()進行深拷貝的時候,對象的所有屬性都添加到target中了。
我們知道了extend()可以進行深拷貝,那麼extend()是如何實現深拷貝的呢?
先來看下jQuery.extend()源碼
主要看下關於深拷貝的部分,取第一個參數,如果是boolean類型的,就賦值給deep,下面如果deep為true(也就是進行深拷貝),就遞歸調用extend(),這樣就將對象的所有屬性都添加到了target中實現了深拷貝。
JSON.parse()和JSON.stringify()
上面的jQuery源碼是否讓你眼花繚亂?有沒有什麼辦法無腦實現深拷貝呢?JSON.parse()和JSON.stringify()給了我們一個基本的解決辦法。
可以看到改變targetCopy並沒有改變原始的target,繼承的屬性也沒有丟失,因此實現了基本的深拷貝。
但是用JSON.parse()和JSON.stringify()會有一個問題。
JSON.parse()和JSON.stringify()能正確處理的對象只有Number、String、Array等能夠被json表示的數據結構,因此函數這種不能被json表示的類型將不能被正確處理。
上面的例子可以看出,hello這個屬性由於是函數類型,使用JSON.parse()和JSON.stringify()後丟失了。
因此JSON.parse()和JSON.stringify()還是需要謹慎使用。
淺 復 制:在複製操作時,對於被複制的對象的每一層複製都是指針複製。
深 復 制:在複製操作時,對於被複制的對象至少有一層複製是對象複製。
完全複製:在複製操作時,對於被複制的對象的每一層複製都是對象複製。
淺層複製:複製引用對象的指針。
深層複製:複製引用對象內容。
retain:始終是淺複製。引用計數每次加一。返回對象是否可變與被複制的對象保持一致。
copy:對於可變對象為深複製,引用計數不改變;對於不可變對象是淺複製, 引用計數每次加一。始終返回一個不可變對象。
mutableCopy:始終是深複製,引用計數不改變。始終返回一個可變對象。
不可變對象:值發生改變,其內存首地址隨之改變。
可變對象:無論值是否改變,其內存首地址都不隨之改變。
那麼先讓我們來看一看下邊數組類型的轉換
1、不可變對象→可變對象的轉換:
NSArray *array1= [NSArray arrayWithObjects:@”a”,@”b”,@”c”,@”d”,nil];
NSMutableArray *str2=[array1 mutableCopy];
2、可變對象→不可變對象的轉換:
NSMutableArray *array2 = [NSMutableArray arrayWithObjects:@”aa”,@”bb”,@”cc”,@”dd”,nil];
NSArray *array1=[ array2 Copy];
3、可變對象→可變對象的轉換(不同指針變量指向不同的內存地址):
NSMutableArray *array1= [NSMutableArray arrayWithObjects:@”a”,@”b”,@”c”,@”d”,nil];
NSMutableArray *str2=[array1 mutableCopy];
通過上邊的兩個例子,我們可輕鬆的將一個對象在可變和不可變之間轉換,並且這裡不用考慮內存使用原則(即引用計數的問題)。沒錯,這就是深拷貝的魅力了。
4、同類型對象之間的指針複製(不同指針變量指向同一塊內存地址):
a、
NSMutableString *str1=[NSMutableString stringWithString:@”two day”];
NSMutableString *str2=[str1 retain];
[str1 release];
b、
NSArray *array1= [NSArray arrayWithObjects:@”a”,@”b”,@”c”,@”d”,nil];
NSArray *str2=[array1 Copy];
[array1 release];
什麼時候用到深淺拷貝?
深拷貝是在要將一個對象從可變(不可變)轉為不可變(可變)或者將一個對象內容克隆一份時用到;
淺拷貝是在要複製一個對象的指針時用到。
數據分為基本數據類型(String, Number, Boolean, Null, Undefined,Symbol)和對象數據類型。
1、基本數據類型的特點:直接存儲在棧(stack)中的數據
2、引用數據類型的特點: 存儲的是該對象在棧中引用,真實的數據存放在堆內存里
引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。當解釋器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中獲得實體。
深拷貝和淺拷貝是只針對Object和Array這樣的引用數據類型的 。
深拷貝和淺拷貝的示意圖大致如下:
淺拷貝只複製指向某個對象的指針,而不複製對象本身,新舊對象還是共享同一塊內存。但深拷貝會另外創造一個一模一樣的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。
當我們把一個對象賦值給一個新的變量時, 賦的其實是該對象的在棧中的地址,而不是堆中的數據 。也就是兩個對象指向的是同一個存儲空間,無論哪個對象發生改變,其實都是改變的存儲空間的內容,因此,兩個對象是聯動的。
淺拷貝是按位拷貝對象, 它會創建一個新對象 ,這個對象有着原始對象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內存地址(引用類型),拷貝的就是內存地址 ,因此如果其中一個對象改變了這個地址,就會影響到另一個對象。即默認拷貝構造函數只是對對象進行淺拷貝複製(逐個成員依次拷貝),即只複製對象空間而不複製資源。
我們先來看兩個例子,對比賦值與淺拷貝會對原對象帶來哪些改變?
上面例子中,obj1是原始數據,obj2是賦值操作得到,而obj3淺拷貝得到。我們可以很清晰看到對原始數據的影響,具體請看下錶:
Object.assign() 方法可以把任意多個的源對象自身的可枚舉屬性拷貝給目標對象,然後返回目標對象。但是 Object.assign() 進行的是淺拷貝,拷貝的是對象的屬性的引用,而不是對象本身。
注意:當object只有一層的時候,是深拷貝
修改新對象會改到原對象:
同樣修改新對象會改到原對象:
關於Array的slice和concat方法的補充說明:Array的slice和concat方法不修改原數組,只會返回一個淺複製了原數組中的元素的一個新數組。
原數組的元素會按照下述規則拷貝:
可能這段話晦澀難懂,我們舉個例子,將上面的例子小作修改:
原理: 用JSON.stringify將對象轉成JSON字符串,再用JSON.parse()把字符串解析成對象,一去一來,新的對象產生了,而且對象會開闢新的棧,實現深拷貝。
這種方法雖然可以實現數組或對象深拷貝,但不能處理函數。
這是因為 JSON.stringify() 方法是將一個JavaScript值(對象或者數組)轉換為一個 JSON字符串,不能接受函數。
遞歸方法實現深度克隆原理: 遍歷對象、數組直到裡邊都是基本數據類型,然後再去複製,就是深度拷貝。
該函數庫也有提供 _.cloneDeep 用來做 Deep Copy。
閱讀原文
看完文章留完言,還有福利拿,往下看???
感興趣的小夥伴可以在公號【grain先森】後台回復【190313】獲取HTML5詳解、CSS3詳解和Vue詳解及實戰項目,可以轉發朋友圈和你的朋友分享哦。
1.深拷貝與淺拷貝 拷貝即是通常所說的複製(Copy)或克隆(Clone),對象的拷貝也就是從現有對象複製一個“一模一樣”的新對象出來。雖然都是複製對象,但是不同的複製方法,複製出來的新對象卻並非完全一模一樣,對象內部存在着一些差異。通常的拷貝方法有兩種,即深拷貝和淺拷貝,那二者之間有何區別呢?MSDN里對IClone接口的Clone方法有這樣的說明:在深層副本中,所有的對象都是重複的;而在淺表副本中,只有頂級對象是重複的,並且頂級以下的對象包含引用。可以看出,深拷貝和淺拷貝之間的區別在於是否複製了子對象。這如何理解呢?下面我通過帶有子對象的代碼來驗證二者的區別。 首先定義兩個類型:Student和ClassRoom,其中Student類型里包含ClassRoom,並使這兩個類型都分別實現自定義的深拷貝接口(IDeepCopy)和淺拷貝接口(IShallowCopy)。 類圖如下: 定義代碼如下: 定義代碼 /// summary /// 深拷貝接口 /// /summary interface IDeepCopy { object DeepCopy(); } /// summary /// 淺拷貝接口 /// /summary interface IShallowCopy { object ShallowCopy(); } /// summary /// 教室信息 /// /summary class ClassRoom : IDeepCopy, IShallowCopy { public int RoomID = 1; public string RoomName = “Room1”; public override string ToString() { return “RoomID=” + RoomID + “\tRoomName=” + RoomName; } public object DeepCopy() { ClassRoom r = new ClassRoom(); r.RoomID = this.RoomID; r.RoomName = this.RoomName; return r; } public object ShallowCopy() { //直接使用內置的淺拷貝方法返回 return this.MemberwiseClone(); } } class Student : IDeepCopy, IShallowCopy { //為了簡化,使用public 字段 public string Name; public int Age; //自定義類型,假設每個Student只擁有一個ClassRoom public ClassRoom Room = new ClassRoom(); public Student() { } public Student(string name, int age) { this.Name = name; this.Age = age; } public object DeepCopy() { Student s = new Student(); s.Name = this.Name; s.Age = this.Age; s.Room = (ClassRoom)this.Room.DeepCopy(); return s; } public object ShallowCopy() { return this.MemberwiseClone(); } public override string ToString() { return “Name:” + Name + “\tAge:” + Age + “\t” + Room.ToString(); } } 測試代碼: 測試代碼 Student s1 = new Student(“Vivi”, 28); Console.WriteLine(“s1=[” + s1 + “]”); Student s2 = (Student)s1.ShallowCopy(); //Student s2 = (Student)s1.DeepCopy(); Console.WriteLine(“s2=[” + s2 + “]”); //此處s2和s1內容相同 Console.WriteLine(“—————————–“); //修改s2的內容 s2.Name = “tianyue”; s2.Age = 25; s2.Room.RoomID = 2; s2.Room.RoomName = “Room2”; Console.WriteLine(“s1=[” + s1 + “]”); Console.WriteLine(“s2=[” + s2 + “]”); //再次打印兩個對象以比較 Console.ReadLine(); 運行結果: a.ShallowCopy s1=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] s2=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] ————————————————————- s1=[Name:Vivi Age:28 RoomID=2 RoomName=Room2] s2=[Name:tianyue Age:25 RoomID=2 RoomName=Room2] b.DeepCopy s1=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] s2=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] —————————– s1=[Name:Vivi Age:28 RoomID=1 RoomName=Room1] s2=[Name:tianyue Age:25 RoomID=2 RoomName=Room2] 從以上結果可以看出,深拷貝時兩個對象是完全“分離”的,改變其中一個,不會影響到另一個對象;淺拷貝時兩個對象並未完全“分離”,改變頂級對象的內容,不會對另一個對象產生影響,但改變子對象的內容,則兩個對象同時被改變。這種差異的產生,即是取決於拷貝子對象時複製內存還是複製指針。深拷貝為子對象重新分配了一段內存空間,並複製其中的內容;淺拷貝僅僅將指針指向原來的子對象。 示意圖如下: 2.淺拷貝與賦值操作 大多數面向對象語言中的賦值操作都是傳遞引用,即改變對象的指針地址,而並沒有複製內存,也沒有做任何複製操作。由此可知,淺拷貝與賦值操作的區別是頂級對象的複製與否。當然,也有一些例外情況,比如類型定義中重載賦值操作符(assignment operator),或者某些類型約定按值傳遞,就像C#中的結構體和枚舉類型。 賦值操作示意圖如下: 3.C++拷貝構造函數 與其它面向對象語言不同,C++允許用戶選擇自定義對象的傳遞方式:值傳遞和引用傳遞。在值傳遞時就要使用對象拷貝,比如說按值傳遞參數,編譯器需要拷貝一個對象以避免原對象在函數體內被破壞。為此,C++提供了拷貝構造函數用來實現這種拷貝行為,拷貝構造函數是一種特殊的構造函數,用來完成一些基於同一類的其它對象的構造和初始化。它唯一的參數是引用類型的,而且不可改變,通常的定義為X(const X)。在拷貝構造函數里,用戶可以定義對象的拷貝行為是深拷貝還是淺拷貝,如果用戶沒有實現自己的拷貝構造函數,那麼編譯器會提供一個默認實現,該實現使用的是按位拷貝(bitwise copy),也即本文所說的淺拷貝。構造函數何時被調用呢?通常以下三種情況需要拷貝對象,此時拷貝構造函數將會被調用。 1.一個對象以值傳遞的方式傳入函數體 2.一個對象以值傳遞的方式從函數返回 3.一個對象需要通過另外一個對象進行初始化 4.C# MemberwiseClone與ICloneable接口 和C++里的拷貝構造函數一樣,C#也為每個對象提供了淺拷貝的默認實現,不過C#里沒有拷貝構造函數,而是通過頂級類型Object里的MemberwiseClone方法。MemberwiseClone 方法創建一個淺表副本,方法是創建一個新對象,然後將當前對象的非靜態字段複製到該新對象。有沒有默認的深拷貝實現呢?當然是沒有,因為需要所有參與拷貝的對象定義自己的深拷貝行為。C++里需要用戶實現拷貝構造函數,重寫默認的淺拷貝;C#則不同,C#(確切的說是.NET Framework,而非C#語言)提供了ICloneable 接口,包含一個成員 Clone,它用於支持除 MemberwiseClone 所提供的克隆之外的克隆。C++通過拷貝構造函數無法確定子對象實現的是深拷貝還是淺拷貝,而C#在“強制”實現淺拷貝的基礎上,提供ICloneable 接口由用戶定義深拷貝行為,通過接口來強制約束所有參與拷貝的對象,個人覺得,這也算是一小點C#對C++的改進。 5.深拷貝策略與實現 深拷貝的要點就是確保所有參與拷貝的對象都要提供自己的深拷貝實現,不管是C++拷貝構造函數還是C#的ICloneable 接口,事實上都是一種拷貝的約定。有了事先的約定,才能約束實現上的統一,所以關鍵在於設計。 但偶爾也會在後期才想到要深拷貝,怎麼辦?總不能修改所有之前的實現吧。有沒有辦法能夠通過頂級類而不關心內部的子對象直接進行深拷貝呢?能不能搞個萬能的深拷貝方法,在想用的時候立即用,而不考慮前期的設計。這樣“大包大攬”的方法,難點在於實現時必須自動獲取子對象的信息,分別為子對象實現深拷貝。C++里比較困難,.NET的反射機制使得實現容易一些。不過這樣的方法雖然通用,實則破壞了封裝,也不符合“每個類對自己負責”的設計原則。 基於.NET的反射機制,以前寫了一個通用的序列化方法,現在可以拿過來,先序列化,然後再反序列化回來,也即是一個深拷貝,示例代碼如下: 深拷貝示例代碼 #region ICloneable Members /// summary /// 此處的複製為深拷貝,在實現上,為了簡化,採用序列化和反序列化。 /// /summary /// returns深拷貝對象/returns public object Clone() { Student stu = new Student(); XmlStorageHelper helper = new XmlStorageHelper(); string strXml = helper.ConvertToString(this); helper.LoadFromString(stu, strXml); //從XML字符串來賦值 return stu; } #endregion
原創文章,作者:簡單一點,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/126807.html