浅谈.net平台下深拷贝和浅拷贝
基本概念:
浅拷贝:指对象的字段被拷贝,而字段引用的对象不会被拷贝,拷贝对象和原对象仅仅是引用名称有所不同,但是它们共用一份实体。对任何一个对象的改变,都会影响到另外一个对象。大部分的引用类型,实现的都是浅拷贝,引用类型对象之间的赋值,就是复制一个对象引用地址的副本,而指向的对象实例仍然是同一个。
深拷贝:指对象的子段被拷贝,同时字段引用的对象也进行了拷贝。深拷贝创建的是整个源对象的结构,拷贝对象和原对象相互独立,不共享任何实例数据,修改一个对象不会影响到另一个对象。值类型之间的赋值操作,执行的就是深拷贝。
基本概念之参考代码:
class program
{
static void main(string[] args)
{
student s1 = new student("li", 23);
//浅拷贝
student s2 = s1;
s2.age = 27;
s1.showinfo();//li's age is 27
//深拷贝
int i = 12;
int j = i;
j = 22;
console.writeline(i);//12
console.read();
}
}
class student
{
public string name;
public int age;
public student(string name, int age)
{
name = name;
age = age;
}
public void showinfo()
{
console.writeline("{0}'s age is {1}", name, age);
}
}
分析:
在上例中,实例s2对s1进行了浅拷贝,对s2中的age字段进行更改,继而影响实例s1中的age字段。
深拷贝中,仅仅是值类型间简单的赋值,对“j”做出的更改不会更改“i”的值。
深浅拷贝的实现:
public object clone()
{
return this.memberwiseclone();
}
memberwiseclone:创建一个浅表副本。过程是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用对象。
参考代码:
class program
{
static void main(string[] args)
{
classa ca = new classa();
ca.value = 88;
classa ca2 = new classa();
ca2 = (classa)ca.clone();
ca2.value = 99;
console.writeline(ca.value + "-----" + ca2.value);//88---99
classb cb = new classb();
cb.member.value = 13;
classb cb2 = (classb)cb.clone();
cb2.member.value = 7;
console.writeline(cb.member.value.tostring() + "------" + cb2.member.value.tostring());//浅拷贝:7---7 深拷贝:13----7
console.read();
}
}
public class classa : icloneable
{
public int value = 0;
public object clone()
{
return this.memberwiseclone();
}
}
public class classb : icloneable
{
public classa member = new classa();
public object clone()
{
//浅拷贝
return this.memberwiseclone();
//深拷贝
classb obj = new classb();
obj.member = (classa)member.clone();
return obj;
}
}
分析:
上例中,ca2复制ca对象,实现了深度拷贝。结果如同代码中显示:ca2中值类型字段的改变并不影响ca中的字段。
在类classb中,引用类型成员member,如果用classa中的clone方法实现则仅仅实现的是浅拷贝,在上述参考代码中能够看出:对cb2的member的改变影响着cb。但是当使用参考代码中的深度拷贝后,对cb2的member的改变则不会影响着cb。
在网上找到一个综合的例子,有对比的来进行解释深浅拷贝:
实例1:
public class sex:icloneable
{
private string _psex;
public string psex
{
set{ _psex = value;}
get { return _psex; }
}
//public object clone()
//{
// return this.memberwiseclone();
//}
}
public class person : icloneable
{
private sex sex = new sex();
public int aa = 3;
public string psex
{
set { sex.psex = value; }
get { return sex.psex; }
}
private string _pname;
public string pname
{
set { this._pname = value; }
get { return this._pname; }
}
public void showpersoninfo()
{
console.writeline("-------------------------");
console.writeline("name:{0} sex:{1}", _pname, this.psex);
console.writeline("-------------------------");
console.writeline(this.aa);
}
//浅拷贝
public object clone()
{
return this.memberwiseclone();
}
//深拷贝
public object deepclone()
{
person newp = new person();
newp.pname = this._pname;
newp.psex = this.psex;
return newp;
}
}
class program
{
static void main(string[] args)
{
console.writeline("原对象:");
person p = new person();
p.pname = "lee";
p.psex = "男";
p.showpersoninfo();//原对象:lee 男 3
//浅拷贝
person copy = (person)p.clone();
//深拷贝
person dcopy = (person)p.deepclone();
console.writeline("修改后的原对象:");
p.pname = "zhao";
p.psex = "女";
p.aa = 1;
p.showpersoninfo();//zhao 女 1
console.writeline("修改后的浅拷贝对象:");
copy.showpersoninfo();//lee 女 3
console.writeline("修改后的深拷贝对象:");
dcopy.showpersoninfo();//lee 男 3
console.writeline("直接拷贝对象:");
person pp = p;
pp.showpersoninfo();//zhao 女 1
console.readline();
}
}
分析:
首先需指出,上例中在类sex中,加入clone方法和不加对实例中运算结果没有影响。
类person中,引用类型但却是string类型的pname字段,引用类型psex字段,值类型aa。
初始值:lee 男 3 (先进行深浅拷贝)
修改值:zhao 女 1
浅拷贝值:lee 女 3
深拷贝值:lee 男 3
直接拷贝值:赵 女 1
结果:上述可以说是对深浅拷贝中经常遇到的几种类型做出总结和对比,相信在一番体悟后可以学到一些知识。
实例2:
class program
{
static void main(string[] args)
{
int[] numbers = { 2, 3, 4, 5 };
int[] numberscopy = new int[5];
numbers.copyto(numberscopy, 0);
numberscopy[2] = 0;
int[] numbers1 = { 2, 3, 4, 5 };
int[] numbersclone1 = (int[])numbers1.clone();
numbersclone1[2] = 0;
console.write(numbers[2] + "---" + numberscopy[2]);//4---0
console.write(numbers1[2] + "---" + numbersclone1[2]);//4--0
//数组的复制也就是引用传递,指向的是同一个地址
int[] numbers2 = { 2, 3, 4, 5 };
int[] numbers2copy = numbers2;
numbers2copy[2] = 0;
console.write(numbers2[2]);//0
console.write(numbers2copy[2]);//0
console.read();
}
}
暂不做分析,认真领悟。
上一篇: Java进阶教程之String类