浅层副本、深层副本的讨论
作者:互联网
现在的很多编程语言都是支持面向对象的编程,封装、继承、多态想必都是很熟悉的,这是面向对象的三大特性。所以讲到构造函数想必也不陌生,但是大多数编程构造函数时,应该都没有想到用深层副本来设计复杂对象,常用的或者是无意识的都是在用浅层副本(当然也是有可能是不用的)。
浅层副本和深层副本定义
浅层副本和深层副本也称浅拷贝和深拷贝,在Martin Fowler写的《Refactoring》(《重构》)中就这个有着具体的论述,作者将这两种副本对象分别称为引用对象(深拷贝)和值对象(浅拷贝)。
先来看看浅层副本(C#语言)
static void Main(string[] args)
{
int[] a = new int[] { 0, 1, 2, 3, 4, 5, };
int[] b = a;
b[0] = 1;
Outputvalue(a);
Outputvalue(b);
Console.ReadKey();
}
private static void Outputvalue(int[]x)
{
for (int i = 0; i < x.Length; i++)
{
if (i == x.Length - 1)
{
Console.WriteLine(x[i]);
}
else
{
Console.Write(x[i]);
}
}
}
让我们来看看运行结果
是不是发现我只改变了一个数组的元素,为什么另一个也改变了,这里不禁好好的想了想,发现这样单纯的复制可能只是让b数组的指向a的内存地址,所以改变b的数组时a也随之改变,这就是浅层复本,那么应该如何避免这种情况发生呢,也就是让b数组不会干扰到a数组,我首先想到的是不让b指向a的内存地址,
所以写了下面的代码
private static int[] deepClone(int[] x)
{
int[] m = new int[x.Length];
for(int i = 0; i < x.Length; i++)
{
m[i] = x[i];
}
return m;
}
private static void Outputvalue(int[]x)
{
for (int i = 0; i < x.Length; i++)
{
if (i == x.Length - 1)
{
Console.WriteLine(x[i]);
}
else
{
Console.Write(x[i]);
}
}
}
static void Main(string[] args)
{
int[] a = new int[] { 0, 1, 2, 3, 4, 5, };
int[] b = deepClone(a);
b[0] = 1;
Outputvalue(a);
Outputvalue(b);
Console.ReadKey();
}
看看运行结果
C#
这是b的改变没有引起a的改变,这可不可以说明深层拷贝就是复制体的内存地址和主体不是在同一处,这时候在深层考虑一下,除了int这样的数据类型,其他的类似于string,char还有引用类型的深层拷贝,又该如何去写呢……
这里附上一个连接,这个博主就其他类型的深拷贝和浅拷贝,有一个比较详细的分析过程。
总结一下
浅拷贝指向了拷贝对象的内存地址,深拷贝则是创造了一个全新的对象,不会影响原来的拷贝对象。
标签:副本,Console,int,浅层,Length,深层,拷贝,Outputvalue 来源: https://blog.csdn.net/weixin_43257287/article/details/88699738