说实话,我也挺晕的,弄了好久才明白过来。
先说一下浅拷贝吧。
浅拷贝分为两种情况,一种是拷贝值类型,一种是拷贝引用类型。
当浅拷贝值类型的时候,浅拷贝就相当于复制一份值出来,注意,这里是值而不是引用,所以当复制出来之后,复制出来的值就与源值是没有关系的了。贴一段代码吧:
类 Test:
[Serializable]
class Test
{
public int i = 0;
public int[] iArr = { 1, 2, 3 };
public String s = "clone";
public Test Clone1() //浅拷贝
{
return this.MemberwiseClone() as Test;
}
public Test Clone2() //深拷贝
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
return formatter.Deserialize(stream) as Test;
}
}
类:Program
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Test t1 = t.Clone1();
Test t2 = t.Clone2();
t1.i = 10;
Console.WriteLine("t:{0}, t1:{1}, t2:{2}", t.i, t1.i, t2.i);
Console.ReadKey();
}
}
结果:
这里会发现当浅拷贝值类型的时候,源值是没有发生改变的,所以这也说明了,当浅拷贝值类型的时候是复制一份出来了,与源值是没有关系的,当然深拷贝也是没有改变的,这很正常,下面会说的。
但是当浅拷贝引用类型的时候,浅拷贝就相当于复制一份引用出来,而地址是不变的还是那个地址,所以当复制出来之后,复制出来的引用改变了,所对应的堆里的数据也是会跟着改变的,源值也会跟着改变。贴一段代码。
类 Test:
[Serializable]
class Test
{
public int i = 0;
public int[] iArr = { 1, 2, 3 };
public String s = "clone";
public Test Clone1() //浅拷贝
{
return this.MemberwiseClone() as Test;
}
public Test Clone2() //深拷贝
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
return formatter.Deserialize(stream) as Test;
}
}
类 Program:
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Test t1 = t.Clone1();
Test t2 = t.Clone2();
t1.iArr[0] = 100;
Console.WriteLine("iArr Clone");
foreach (var v in t.iArr)
{
Console.WriteLine(v);
}
Console.WriteLine("iArr Clone1");
foreach (var v in t1.iArr)
{
Console.WriteLine(v);
}
Console.WriteLine("iArr Clone2");
foreach (var v in t2.iArr)
{
Console.WriteLine(v);
}
Console.ReadKey();
}
}
结果:
这里会发现当t1的iArr[0]发生改变的时候,源值iArr[0]也改变了,而t2的iArr[0]是没有任何变化的。
但是,注意这个但是啊!
string类型是引用类型,这是大家都知道的吧,不用我说吧,enmmmm,不知道的人可以查一下。
当浅拷贝string类型的时候,当拷贝出来的值发生改变的时候,源值也是会发生变化的,是不是很不可思议。没错,就是这么不可思议,贴上代码。
类 Test:
[Serializable]
class Test
{
public int i = 0;
public int[] iArr = { 1, 2, 3 };
public String s = "clone";
public Test Clone1() //浅拷贝
{
return this.MemberwiseClone() as Test;
}
public Test Clone2() //深拷贝
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
return formatter.Deserialize(stream) as Test;
}
}
类 Program:
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Test t1 = t.Clone1();
Test t2 = t.Clone2();
t1.s = "copy";
Console.WriteLine("t:{0}, t1:{1}, t2:{2}", t.s, t1.s, t2.s);
Console.WriteLine("");
Console.ReadKey();
}
}
结果:
这里会发现当t1发生变化的情况下,源值t居然没发生变化,按理说应该是会有变化的,别急,下面有说法。
原因就是:
我们看一下string的源代码就可以理解了
//表示空字符串。此字段为只读。 |
public static readonly string Empty; |
string类型是只读的,当string值改变的时候,会重新分配地址的哦,这样子就与源值是没有任何关系的了。
那么现在说说深拷贝吧!
深拷贝就是拷贝了,无论是值类型还是引用类型,改变拷贝出来的数据都不会影响源值的数据的。
好了就说到这里啦,有疑问的或者感觉我说的不对的地方,欢迎指导哈。