http://www.cnblogs.com/shuaiwhu/archive/2010/12/14/2065088.html
深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在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()方法进行改写,则调用此方法得到的对象即为浅拷贝,下面我们着重谈一下深拷贝。
运行下面的程序,看一看浅拷贝:
class Professor0
implements Cloneable
{ String
name; int age; Professor0(String
name, int age)
{ this .name
= name; this .age
= age; } public Object
clone() throws CloneNotSupportedException
{ return super .clone(); } } class Student0
implements Cloneable
{ String
name; //
常量对象。 int age; Professor0
p; //
学生1和学生2的引用值都是一样的。 Student0(String
name, int age,
Professor0 p) { this .name
= name; this .age
= age; this .p
= p; } public Object
clone() { Student0
o = null ; try { o
= (Student0) super .clone(); }
catch (CloneNotSupportedException
e) { System.out.println(e.toString()); } return o; } } public class ShallowCopy
{ public static void main(String[]
args) { Professor0
p = new Professor0( "wangwu" ,
50 ); Student0
s1 = new Student0( "zhangsan" ,
18 ,
p); Student0
s2 = (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指向的是同一个对象。这在我们有的实际需求中,却不是这样,因而我们需要深拷贝:
class Professor
implements Cloneable
{ String
name; int age; Professor(String
name, int age)
{ this .name
= name; this .age
= age; } public Object
clone() { Object
o = null ; try { o
= super .clone(); }
catch (CloneNotSupportedException
e) { System.out.println(e.toString()); } return o; } } class Student
implements Cloneable
{ String
name; int age; Professor
p; Student(String
name, int age,
Professor p) { this .name
= name; this .age
= age; this .p
= p; } public Object
clone() { Student
o = null ; try { o
= (Student) super .clone(); }
catch (CloneNotSupportedException
e) { System.out.println(e.toString()); } o.p
= (Professor) p.clone(); return o; } } public class DeepCopy
{ public static void main(String
args[]) { long t1
= System.currentTimeMillis(); Professor
p = new Professor( "wangwu" ,
50 ); Student
s1 = new Student( "zhangsan" ,
18 ,
p); Student
s2 = (Student) s1.clone(); s2.p.name
= "lisi" ; s2.p.age
= 30 ; System.out.println( "name=" +
s1.p.name + "," +
"age=" +
s1.p.age); //
学生1的教授不改变。 long t2
= System.currentTimeMillis(); System.out.println(t2-t1); } } |
当然我们还有一种深拷贝方法,就是将对象串行化:
import java.io.*; //Serialization
is time-consuming class Professor2
implements Serializable
{ /** *
*/ private static final long serialVersionUID
= 1L; String
name; int age; Professor2(String
name, int age)
{ this .name
= name; this .age
= age; } } class Student2
implements Serializable
{ /** *
*/ private static final long serialVersionUID
= 1L; String
name; //
常量对象。 int age; Professor2
p; //
学生1和学生2的引用值都是一样的。 Student2(String
name, int age,
Professor2 p) { this .name
= name; this .age
= age; this .p
= p; } public Object
deepClone() throws IOException,
OptionalDataException, ClassNotFoundException
{ //
将对象写到流里 ByteArrayOutputStream
bo = new ByteArrayOutputStream(); ObjectOutputStream
oo = new ObjectOutputStream(bo); oo.writeObject( this ); //
从流里读出来 ByteArrayInputStream
bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream
oi = new ObjectInputStream(bi); return (oi.readObject()); } } public class DeepCopy2
{ /** *
@param args */ public static void main(String[]
args) throws OptionalDataException, IOException,
ClassNotFoundException { long t1
= System.currentTimeMillis(); Professor2
p = new Professor2( "wangwu" ,
50 ); Student2
s1 = new Student2( "zhangsan" ,
18 ,
p); Student2
s2 = (Student2) s1.deepClone(); s2.p.name
= "lisi" ; s2.p.age
= 30 ; System.out.println( "name=" +
s1.p.name + "," +
"age=" +
s1.p.age); //
学生1的教授不改变。 long t2
= System.currentTimeMillis(); System.out.println(t2-t1); } } |
但是串行化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。