Java中的深拷贝(深复制)和浅拷贝(浅复制)介绍
深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java。虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑。
浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。举例来说更加清楚:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2中包含对C2(C1的copy)的引用。
若不对clone()方法进行改写,则调用此方法得到的对象即为浅拷贝,下面我们着重谈一下深拷贝。
运行下面的程序,看一看浅拷贝:
classProfessor0implementsCloneable{
Stringname;
intage;
Professor0(Stringname,intage){
this.name=name;
this.age=age;
}
publicObjectclone()throwsCloneNotSupportedException{
returnsuper.clone();
}
}
classStudent0implementsCloneable{
Stringname;//常量对象。
intage;
Professor0p;//学生1和学生2的引用值都是一样的。
Student0(Stringname,intage,Professor0p){
this.name=name;
this.age=age;
this.p=p;
}
publicObjectclone(){
Student0o=null;
try{
o=(Student0)super.clone();
}catch(CloneNotSupportedExceptione){
System.out.println(e.toString());
}
returno;
}
}
publicclassShallowCopy{
publicstaticvoidmain(String[]args){
Professor0p=newProfessor0("wangwu",50);
Student0s1=newStudent0("zhangsan",18,p);
Student0s2=(Student0)s1.clone();
s2.p.name="lisi";
s2.p.age=30;
s2.name="z";
s2.age=45;
System.out.println("学生s1的姓名:"+s1.name+"\n学生s1教授的姓名:"+s1.p.name+","+"\n学生s1教授的年纪"+s1.p.age);//学生1的教授
}
}
s2变了,但s1也变了,证明s1的p和s2的p指向的是同一个对象。这在我们有的实际需求中,却不是这样,因而我们需要深拷贝:
classProfessorimplementsCloneable{
Stringname;
intage;
Professor(Stringname,intage){
this.name=name;
this.age=age;
}
publicObjectclone(){
Objecto=null;
try{
o=super.clone();
}catch(CloneNotSupportedExceptione){
System.out.println(e.toString());
}
returno;
}
}
classStudentimplementsCloneable{
Stringname;
intage;
Professorp;
Student(Stringname,intage,Professorp){
this.name=name;
this.age=age;
this.p=p;
}
publicObjectclone(){
Studento=null;
try{
o=(Student)super.clone();
}catch(CloneNotSupportedExceptione){
System.out.println(e.toString());
}
o.p=(Professor)p.clone();
returno;
}
}
publicclassDeepCopy{
publicstaticvoidmain(Stringargs[]){
longt1=System.currentTimeMillis();
Professorp=newProfessor("wangwu",50);
Students1=newStudent("zhangsan",18,p);
Students2=(Student)s1.clone();
s2.p.name="lisi";
s2.p.age=30;
System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授不改变。
longt2=System.currentTimeMillis();
System.out.println(t2-t1);
}
}
当然我们还有一种深拷贝方法,就是将对象串行化:
importjava.io.*;
//Serializationistime-consuming
classProfessor2implementsSerializable{
/**
*
*/
privatestaticfinallongserialVersionUID=1L;
Stringname;
intage;
Professor2(Stringname,intage){
this.name=name;
this.age=age;
}
}
classStudent2implementsSerializable{
/**
*
*/
privatestaticfinallongserialVersionUID=1L;
Stringname;//常量对象。
intage;
Professor2p;//学生1和学生2的引用值都是一样的。
Student2(Stringname,intage,Professor2p){
this.name=name;
this.age=age;
this.p=p;
}
publicObjectdeepClone()throwsIOException,OptionalDataException,
ClassNotFoundException{
//将对象写到流里
ByteArrayOutputStreambo=newByteArrayOutputStream();
ObjectOutputStreamoo=newObjectOutputStream(bo);
oo.writeObject(this);
//从流里读出来
ByteArrayInputStreambi=newByteArrayInputStream(bo.toByteArray());
ObjectInputStreamoi=newObjectInputStream(bi);
return(oi.readObject());
}
}
publicclassDeepCopy2{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args)throwsOptionalDataException,
IOException,ClassNotFoundException{
longt1=System.currentTimeMillis();
Professor2p=newProfessor2("wangwu",50);
Student2s1=newStudent2("zhangsan",18,p);
Student2s2=(Student2)s1.deepClone();
s2.p.name="lisi";
s2.p.age=30;
System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授不改变。
longt2=System.currentTimeMillis();
System.out.println(t2-t1);
}
}
但是串行化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。