1
????????
什么是
Clone
,容易實現(xiàn)嗎?
簡單地說,
Clone
就是對于給定的一個對象實例
o
,得到另一個對象實例
o’
:
o
與
o’
類
型相同(
o.getClass() == o’.getClass()
),內(nèi)容相同(對于
o/o’
中的字段
f
,如果
f
是基本數(shù)據(jù)類型,則
o.f == o’.f
;如果
f
是對象引用,則
o.f == o’.f
或
o.f
指向的對象與
o’.f
指向的對象的內(nèi)容相同)。通常稱
o’
為
o
的克隆或副本。
??????
直觀上看,似乎很容易為一個類加上
clone
方法:
class A {
?????? private Type1 field1;
??? private Type2 field2;
???? …..
??? public Object clone() {
????????????? A a = new A();
??????? a.field1 = a.getField1();
??????? a.field2 = a.getField2();
??????? ……
??????? return a;
??? }
}
|
?
然而,稍加推敲,就會發(fā)現(xiàn)這樣的實現(xiàn)方法有兩個問題:
1.????????
要想某個類有
clone
功能,必須單獨為其實現(xiàn)
clone()
函數(shù),函數(shù)實現(xiàn)代碼與該類定義密切相關(guān)。
2.????????
即使基類
A
已有
clone()
函數(shù),其子類
ExtendA
若要具備
clone
功能,則必須
override
其基類
A
的
clone()
函數(shù)。否則,對類型為
ExtendA
的對象
ea
的
clone()
方法的調(diào)用,會執(zhí)行于類
A
中定義的
clone()
方法而返回一個類型為
A
的對象,它顯然不是
ea
的克隆。
2
????????
Java
對
clone
的支持
萬類之初的
Object
類有
clone()
方法:
protected native Object clone() throws CloneNotSupportedException;
|
該方法是
protected
的,顯然是留待被子類
override
的。該方法又是
native
的,必然做了
與具體平臺相關(guān)的底層工作。
事實上,類
Object
的
clone()
方法首先會檢查
this.getClass()
是否實現(xiàn)了
Cloneable
接口。
Cloneable
只是一個標(biāo)志接口而已,用來標(biāo)志該類是否有克隆功能。
public
interface
Cloneable {
}
|
??????
如果
this.getClass()
沒有實現(xiàn)
Cloneable
接口,
clone()
就會拋
CloneNotSupportedException
返回。否則就會創(chuàng)建一個類型為
this.getClass()
的對象
other
,并將
this
各
field
的值賦值給
other
的對應(yīng)
field
,然后返回
other
。
??????
如此一來,我們要定義一個具有
Clone
功能的類就相當(dāng)方便:
1.????????
在類的聲明中加入“
implements Cloneable
”,標(biāo)志該類有克隆功能;
2.????????
Override
類
Object
的
clone()
方法,在該方法中調(diào)用
super.clone()
:
class CloneableClass implements Cloneable {
?????? ……
public Object clone() {
?????? try {
??????
?????? return super.clone();
//
直接讓
Object.clone()
為我們代勞一切
??? } catch (CloneNotSupportedException e) {
??????
?????? throw new InternalError();
?????? }
}
}
|
?
3
????????
Shallow Clone
與
Deep Clone
3.1
???
Shallow
與
Deep
從何而來
一個具有克隆功能的類,如果有可變(
Mutable
)類類型的字段
field
,如何為其克隆(副
本)對象
o’
中的
field
賦值?
??????
方法一、如
Object
的
clone()
方法所實現(xiàn):設(shè)原始對象為
o
,其克隆對象是
o’
,執(zhí)行
o’.field = o.field
。這樣,
o’.field
與
o.field
指向同一個可變對象
m
。
o
與
o’
可能會相互影響(一個對象的狀態(tài)可能會隨著另一個對象的狀態(tài)的改變而改變)。這樣的
Clone
稱為
Shallow Clone
。這也是
Object
的
clone()
方法的實現(xiàn)方式。
??????
方法二、將
o.field
指向的可變對象
m
克隆,得到
m’
,將
m’
的引用賦值給
o’.field
。這樣
o’
與
o
內(nèi)容相同,且相互之間無影響(一個對象狀態(tài)的改變不會影響另一個對象的狀態(tài))。這樣的
Clone
稱為
Deep Clone
。
?????? Java Collection
類庫中具體數(shù)據(jù)結(jié)構(gòu)類(
ArrayList/LinkedList
,
HashSet/TreeSet
,
HashMap/TreeMap
等)都具有克隆功能,且都是
Shallow Clone
,這樣設(shè)計是合理的,因為它們不知道存放其中的每個數(shù)據(jù)對象是否也有克隆功能。
System.arrayCopy()
的實現(xiàn)采用的也是
Shallow Clone
。
?????? Deep Clone
對于實現(xiàn)不可變(
Immutable
)類很有幫助。設(shè)一個類包含可變類
M
類型的
field
,如何將其設(shè)計為不可變類呢?先為
M
實現(xiàn)
Deep Clone
功能,然后這樣設(shè)計類
ImmutableClass
:
class ImmutableClass {
?????? MutableClass m;
ImmutableClass(MutableClass m) {
?????? this.m = m.clone();
//
將傳入的
m
的
clone
賦值給內(nèi)部
m
}
public MutableClass getM() {
??? return this.m.clone();
//
將內(nèi)部
m
的
clone
返回給外部
}
}
|
?
??????
3.2
???
如何實現(xiàn)
Deep Clone
檢查類有無可變類類型的字段。如果無,返回
super.clone()
即可;
如果有,確保包含的可變類本身都實現(xiàn)了
Deep Clone
;
Object o = super.clone();
//
先執(zhí)行淺克隆,確保類型正確和基本類型及非可變類類型字段內(nèi)容正確
對于每一個可變類類型的字段
field
:
?????? o.field = this.getField().clone();
返回
o
。