先引入一个观念,赋值和深复制、浅复制并不是一样的,含义是不一样的。
本文所说的主要是针对“ 引用类型 ”本文以 “类 ”为例加以说明。一般的系统定义的值类型(int、double、float等等)此处不做考虑。
1、赋值。指的是 “ 等号= ”。它相当于是给引用对象起一个别名。
2、浅度复制和深度复制。指的是类实现 ICloneable接口,重写该接口的唯一方法。注意:不管是深度复制还是浅度复制,都是通过ICloneable接口去实现的。
1、赋值
此处定义了一个父亲类Parent,他有三个属性 年龄Age,身高Height,孩子信息child,但是孩子信息又包含三个信息,即姓名Name,年龄Age,体重Weight。对于父类Parent而言,Age、Height是“ 值类型 ”,而成员child是“ 引用类型 ”。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 赋值_深度复制_浅度复制
{
class Program
{
static void Main(string[] args)
{
Parent parent_01 = new Parent();
parent_01.Age = 48;
parent_01.Height = 173;
parent_01.child = new Children("菲菲", 25, 55.55);
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
Parent parent_02 = parent_01;
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
Console.WriteLine("===========================================");
parent_02.Age = 60;
parent_02.Height = 189;
parent_02.child.Age = 35;
parent_02.child.Name = "宝宝";
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
}
}
class Parent
{
private int age;
private double height;
public Children child;
public Parent()
{
}
public int Age { get => age; set => age = value; }
public double Height { get => height; set => height = value; }
}
class Children
{
private string name;
private int age;
private double weight;
public Children(string name,int age,double weight)
{
this.name = name;
this.age = age;
this.weight = weight;
}
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
public double Weight { get => weight; set => weight = value; }
}
}
运行结果如下:
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
===========================================
年龄:60 身高:189 孩子的信息为:宝宝 35 55.55
年龄:60 身高:189 孩子的信息为:宝宝 35 55.55
请按任意键继续. . .
===================================================================
总结:parent_01和parent_02完全是共用的,不管是引用类型成员,还是值类型成员,都是共用的,parent_02任何成员改变,parent_01都会跟着改变。
2、浅复制
给父类Parent实现ICloneable接口,重写Clone方法,注意,默认的MemberWiseClone()就是系统实现的“ 浅度复制 ”。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 浅复制
{
class Program
{
static void Main(string[] args)
{
Parent parent_01 = new Parent();
parent_01.Age = 48;
parent_01.Height = 173;
parent_01.child = new Children("菲菲", 25, 55.55);
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
Parent parent_02 = parent_01.Clone() as Parent;
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
Console.WriteLine("===========================================");
parent_02.Age = 60;
parent_02.Height = 189;
parent_02.child.Age = 35;
parent_02.child.Name = "宝宝";
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
}
}
class Parent:ICloneable
{
private int age;
private double height;
public Children child;
public Parent()
{
}
public int Age { get => age; set => age = value; }
public double Height { get => height; set => height = value; }
public object Clone()
{
return this.MemberwiseClone(); //浅复制
}
}
class Children
{
private string name;
private int age;
private double weight;
public Children(string name, int age, double weight)
{
this.name = name;
this.age = age;
this.weight = weight;
}
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
public double Weight { get => weight; set => weight = value; }
}
}
运行结果为:
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
===========================================
年龄:48 身高:173 孩子的信息为:宝宝 35 55.55
年龄:60 身高:189 孩子的信息为:宝宝 35 55.55
请按任意键继续. . .
总结:从上可以看出,对于父亲类Parent的值类型成员,parent_01和parent_02是不共用的,parent_02改变,parent_01独立的,并不会改变;但是对于引用类型成员child,parent_01和parent_02是共用的,parent_02改变,parent_01也会跟着改变。
3、深度复制
深度复制的实现和浅度复制类似,只不过是重载的Clone方法实现不一样,具体可参见代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 深复制
{
class Program
{
static void Main(string[] args)
{
Parent parent_01 = new Parent();
parent_01.Age = 48;
parent_01.Height = 173;
parent_01.child = new Children("菲菲", 25, 55.55);
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
Parent parent_02 = parent_01.Clone() as Parent;
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
Console.WriteLine("===========================================");
parent_02.Age = 60;
parent_02.Height = 189;
parent_02.child.Age = 35;
parent_02.child.Name = "宝宝";
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_01.Age, parent_01.Height, parent_01.child.Name, parent_01.child.Age, parent_01.child.Weight);
Console.WriteLine("年龄:{0} 身高:{1} 孩子的信息为:{2} {3} {4}", parent_02.Age, parent_02.Height, parent_02.child.Name, parent_02.child.Age, parent_02.child.Weight);
}
}
class Parent : ICloneable
{
private int age;
private double height;
public Children child;
public Parent()
{
}
public int Age { get => age; set => age = value; }
public double Height { get => height; set => height = value; }
public object Clone()
{
Parent newparent = new Parent();
newparent.Age = 48;newparent.Height = 173;
newparent.child = new Children("菲菲", 25, 55.55);
Object newParent = newparent;
return newParent; //深复制
}
}
class Children
{
private string name;
private int age;
private double weight;
public Children(string name, int age, double weight)
{
this.name = name;
this.age = age;
this.weight = weight;
}
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
public double Weight { get => weight; set => weight = value; }
}
}
运行结果为:
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
===========================================
年龄:48 身高:173 孩子的信息为:菲菲 25 55.55
年龄:60 身高:189 孩子的信息为:宝宝 35 55.55
请按任意键继续. . .
总结:从上可以看出,对于父亲类Parent的所有成员,parent_01和parent_02是完全不共用的,parent_02改变,不管是改变父亲类Parent的值类型成员,还是应用类型成员,parent_01都是独立的,并不会改变。
有兴趣的可以参考python的深度复制和浅度复制,有类似的地方。