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