浅拷贝与深拷贝
再讲之前我们来解释下拷贝,顾名思义就是复制的意思。和物理上的拷贝不一样,在面向对象语言中拷贝涉及到类的继承、接口的实现等等。下面我们来讨论下浅拷贝与深拷贝的一些作用于区别。
拷贝:一定要有一个新对象的出现,并且这两个对象一定要相同。
下面是浅拷贝的一个例子:
1 class Person{ 2 public string name; 3 public int age; 4 public char gender; 5 Random r; 6 public Person(string name,int age,char gender){ 7 this.name=name; 8 this.age=age; 9 this.gender=r.Next(2)==1?'男':'女'; 10 } 11 } 12 Person p1=new Person("张三",18,'男'); 13 //浅拷贝方法1:直接赋值拷贝创建对象 14 Person p2=new Person(p1.name,p1.age,p1.gender); 15 //浅拷贝方法2:使用类的初始化器创建对象 16 Person p3=new Person(){name=p1.name,age=p1.age,gender=p1.gender};
但是这种两种拷贝方法却又一个缺陷,就是当内部变量赋值出现不可预测的因素时(Person类中的性别就是不可控因素),不能保证拷贝后的对象与之前的对象一样。所有我们提出了一个新的解决方案如下:
思路:使用object类提供的一个受保护的方法来实现浅拷贝
①在对象中添加一个方法。
②该方法的返回值就是该类类型。
③return (该类类型)this.MemberwiseClone();
代码如下:
1 class Person{ 2 public string name; 3 public int age; 4 public char gender; 5 public Person(string name,int age,char gender){ 6 this.name=name; 7 this.age=age; 8 this.gender=gender; 9 } 10 public Person Clone(){ 11 return (Person)this.MemberwiseClone(); 12 } 13 } 14 Person p1=new Person("张三",18,'男'); 15 Person p2=p1.Clone();
浅拷贝就不考虑对象中的引用类型成员,只是将对象中的内容全部拷贝一份,对于引用类型就是拷贝其存储的值,即地址。
而深拷贝就是把对象的所有成员都拷贝一份,包括引用类型成员。但考虑到类中的引用类型有可能有很多或者以后会添加新的引用类型。我这里直接介绍一种最直接的方法。
思路:通过对对象的序列化和反序列化来拷贝对象
1 class Person{ 2 public string name; 3 public int age; 4 public char gender; 5 public Car MyCar; 6 public Person(string name,int age,char gender,string carName){ 7 this.name=name; 8 this.age=age; 9 this.gender=gender; 10 MyCar=new Car(); 11 MyCar.name=carName; 12 } 13 public Person Clone(){ 14 return (Person)this.MemberwiseClone(); 15 } 16 } 17 class Car{ 18 public string name; 19 } 20 //序列化对象 21 Person p1 = new Person("张三", 18, '男'); 22 //创建二进制流对象 23 BinaryFormatter bf = new BinaryFormatter(); 24 using (FileStream fs = new FileStream(@"E:1.dat", FileMode.Create, FileAccess.Write)) { 25 bf.Serialize(fs, p1); 26 } 27 //反序列化dat文件 28 //创建二进制流对象 29 BinaryFormatter bf1 = new BinaryFormatter(); 30 //创建一个Persond对象来接收反序列化读的对象 31 Person p2; 32 using (FileStream fs1 = new FileStream(@"E:1.dat", FileMode.Open, FileAccess.Read)) { 33 p2 = (Person)bf1.Deserialize(fs1); 34 }