天天看点

深拷贝和浅拷贝示例

关于深拷贝和浅拷贝的文章已经颇多。http://cnn237111.blog.51cto.com/2359144/589507

简单的说,深拷贝和浅拷贝都是拷贝对象。但是当拷贝的对象中有包含引用类型对象时,深拷贝和浅拷贝的做法就又不一样了。

浅拷贝对该子对象只是拷贝了一个引用,实际上指向的还是拷贝对象的那份数据。

深拷贝则不然,是重新开辟内存空间,将子对象玩玩整整的复制一份。

下面是一个演示的例子。

在看演示之前,对几个方法做一下说明。

object.ReferenceEquals方法,比较两个实例是否是引用了同一个对象,即两个引用变量指向的是同一个内存地址。不要去对值类型调用ReferenceEquals方法,因为ReferenceEquals接收的是object类型,值类型传进去后会被装箱,每次装箱都会有一个新的地址,因此两个相等的值类型传进去,得到的结果也是false。

ObjectIDGenerator.GetId方法,该方法是获得指定对象的ID,同样的对值类型数据,不要调用此方法。

MemberwiseClone()方法,该方法创建当前 Object 的浅表副本,即返回当前对象的一个浅拷贝。下面摘自MSDN:

MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

MemberwiseClone方法是protected的,因此只能在类内部,或者派生类中使用。要实现深拷贝的话,还需自己实现。

在下面的演示中,可以看到string变量的违法常规的特殊行为,这是由于字符串的驻留的机制,可以参考文章:http://www.cnblogs.com/artech/archive/2007/03/04/663728.html

示例代码:

  1. namespace ConsoleApplication1 
  2.     class Program 
  3.     { 
  4.         static ObjectIDGenerator IDGenerator = new ObjectIDGenerator(); 
  5.         static void Main(string[] args) 
  6.         { 
  7.             bool isFirstTime; 
  8.             testObject t1 = new testObject(); 
  9.             testObject t2 = t1.ShallowCopy(); 
  10.             Console.WriteLine("浅拷贝后......"); 
  11.             Console.WriteLine(string.Format("t1的ObjectID={0}。t2的ObjectID={1}。ReferenceEquals(t1, t2)={2}", IDGenerator.GetId(t1, out isFirstTime), IDGenerator.GetId(t2, out isFirstTime), object.ReferenceEquals(t1, t2))); 
  12.             Console.WriteLine(string.Format("t1.i == t2.i {0}",t1.i == t2.i)); 
  13.             Console.WriteLine(string.Format("t1.s的ObjectID={0}。t2.s的ObjectID={1}。ReferenceEquals(t1.s, t2.s)={2}", IDGenerator.GetId(t1.s, out isFirstTime), IDGenerator.GetId(t2.s, out isFirstTime), object.ReferenceEquals(t1.s, t2.s))); 
  14.             Console.WriteLine(object.ReferenceEquals(t1.sb, t2.sb)); 
  15.             Console.WriteLine(string.Format("t1.sb的ObjectID={0}。t2.sb的ObjectID={1}。ReferenceEquals(t1.sb, t2.sb)={2}", IDGenerator.GetId(t1.sb, out isFirstTime), IDGenerator.GetId(t2.sb, out isFirstTime), object.ReferenceEquals(t1.sb, t2.sb))); 
  16.             Console.WriteLine(); 
  17.             testObject t3 = t1.DeepCopy(); 
  18.             Console.WriteLine("深拷贝后......"); 
  19.             Console.WriteLine(string.Format("t1的ObjectID={0}。t3的ObjectID={1}。ReferenceEquals(t1, t3)={2}", IDGenerator.GetId(t1, out isFirstTime), IDGenerator.GetId(t3, out isFirstTime), object.ReferenceEquals(t1, t3))); 
  20.             Console.WriteLine(string.Format("t1.i == t3.i {0}", t1.i == t3.i)); 
  21.             Console.WriteLine(string.Format("t1.s的ObjectID={0}。t3.s的ObjectID={1}。ReferenceEquals(t1.s, t3.s)={2}", IDGenerator.GetId(t1.s, out isFirstTime), IDGenerator.GetId(t3.s, out isFirstTime), object.ReferenceEquals(t1.s, t3.s))); 
  22.             Console.WriteLine(object.ReferenceEquals(t1.sb, t3.sb)); 
  23.             Console.WriteLine(string.Format("t1.sb的ObjectID={0}。t3.sb的ObjectID={1}。ReferenceEquals(t1.sb, t3.sb)={2}", IDGenerator.GetId(t1.sb, out isFirstTime), IDGenerator.GetId(t3.sb, out isFirstTime), object.ReferenceEquals(t1.sb, t3.sb))); 
  24.         } 
  25.     } 
  26.     public class testObject 
  27.     { 
  28.         public int i = 0; 
  29.         public string s = ""; 
  30.         public StringBuilder sb = new StringBuilder(); 
  31.         public testObject ShallowCopy() 
  32.         { 
  33.             return (testObject)this.MemberwiseClone(); 
  34.         } 
  35.         public testObject DeepCopy() 
  36.         { 
  37.             testObject other = (testObject)this.MemberwiseClone(); 
  38.             other.s = new String(this.s.ToCharArray()); 
  39.             other.sb = new StringBuilder(this.sb.ToString()); 
  40.             return other; 
  41.         } 
  42.     } 

运行结果:

深拷贝和浅拷贝示例

继续阅读