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); } }
但是串行化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。