我正在尋找一些教程來解釋有關Java Cloneable
,但沒有得到任何好的鏈接,堆棧溢出越來越明顯的選擇。關於Java可複製
我想了解以下內容:
Cloneable
意味着我們可以有一個克隆或對象的副本,通過 實現Cloneable
接口。這樣做的缺點是什麼?- 如果對象是 組合對象,遞歸克隆是如何發生的?
謝謝。
我正在尋找一些教程來解釋有關Java Cloneable
,但沒有得到任何好的鏈接,堆棧溢出越來越明顯的選擇。關於Java可複製
我想了解以下內容:
Cloneable
意味着我們可以有一個克隆或對象的副本,通過 實現Cloneable
接口。這樣做的缺點是什麼?謝謝。
您應該知道的關於Cloneable
的第一件事是 - 不要使用它。
這是很難實現與Cloneable
克隆權利,並且努力是不值得的。
而不是使用其他選項,如apache-commons SerializationUtils
(深度克隆)或BeanUtils
(淺 - 克隆),或者只是使用複製構造函數。
See here喬希布洛赫關於克隆與Cloneable
,這解釋了該方法的許多缺點的意見。 (Joshua Bloch是Sun的一名員工,並領導開發了許多Java功能。)
所以,明智地使用Cloneable。與您爲了做正確事情而需要申請的努力相比,它並沒有給您帶來足夠的好處。
正如Bozho所說,不要使用Cloneable。相反,使用複製構造函數。 http://www.javapractices.com/topic/TopicAction.do?Id=12 – Bane 2010-11-02 20:47:54
@Bane,如果你不知道要克隆的對象的類型,如何知道要調用哪個類的拷貝構造函數? – 2010-11-02 22:55:32
@Steve:我不關注。如果你要克隆一個對象,我認爲你已經知道它是什麼類型 - 畢竟,你有計劃克隆的對象。如果有一種情況,你的對象已經失去了它的具體類型,更通用的,你不能使用一個簡單的'實例'來評估它? – Bane 2010-11-03 13:47:45
A)複製構造函數克隆沒有很多優點。可能最大的一個是創建完全相同動態類型的新對象(假設聲明的類型是可克隆的並具有公共克隆方法)。 B)默認克隆創建一個淺拷貝,並且它將保持一個淺拷貝,除非你的克隆實現改變了它。這可能是困難的,特別是如果你的班級有最後的字段
Bozho是正確的,克隆可能很難得到正確的。複製構造函數/工廠將滿足大多數需求。
Cloneable本身不幸只是一個標記接口,即:它沒有定義clone()方法。
什麼是確定是否會改變受保護的Object.clone()方法的行爲,該方法將爲未實現Cloneable的類拋出CloneNotSupportedException,併爲類所在的類執行成員級淺表副本。
即使這是您正在尋找的行爲,您仍然需要實現自己的clone()方法以公開它。
在實現自己的clone()時,想法是先從super.clone()創建對象,並確保它是正確的類,然後在出現淺度時添加任何字段複製不是你想要的。從clone()調用構造函數會有問題,因爲如果子類想要添加自己的額外的可複製邏輯,這會破壞繼承;如果要調用super.clone(),則在這種情況下會得到錯誤類的對象。
該方法繞過了可能在您的構造函數中定義的任何邏輯,這可能會造成問題。
另一個問題是,任何忘記覆蓋clone()的子類都會自動繼承默認的淺拷貝,這可能不是你想要的在可變狀態的情況下(它現在將在源和拷貝之間共享) 。
大多數開發人員不會因爲這些原因而使用Cloneable,而只是簡單地實現一個複製構造函數。
欲瞭解更多信息和Cloneable的潛在的陷阱,我強烈建議書有效的Java由約書亞布洛赫
克隆是一個基本的編程範式。 Java可能以很多方式實施它的事實根本不會減少克隆的需要。而且,很容易實現可以工作的克隆,但是您希望它能夠工作,淺層,深層,混合等等。你甚至可以使用名稱克隆的功能,而不是實現克隆,如果你喜歡。
假設我有類A,B和C,其中B和C是從A派生如果我有這樣一個類型的對象的列表:
ArrayList<A> list1;
現在,該列表可以包含類型A,B或C的對象。您不知道對象是什麼類型。所以,你不能複製名單如下:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}
如果對象實際上是B或C類的,你就不會得到正確的副本。而且,如果A是抽象的呢?現在,有人提出這樣的建議:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
if(a instanceof A) {
list2.add(new A(a));
} else if(a instanceof B) {
list2.add(new B(a));
} else if(a instanceof C) {
list2.add(new C(a));
}
}
這是一個非常非常糟糕的主意。如果你添加一個新的派生類型呢?如果B或C在另一個包裝中,並且您無法在此課程中使用它們,該怎麼辦?
什麼你想要做的是這樣的:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}
很多人都表示,爲什麼克隆的基本Java實現是有問題的。但是,它很容易克服這樣:
在A類:
public A clone() {
return new A(this);
}
在B類:
@Override
public B clone() {
return new B(this);
}
在C類:
@Override
public C clone() {
return new C(this):
}
我不執行可複製的,只是使用相同的函數名稱。如果你不喜歡這個,就把它命名爲別的。
Cloneable的缺點是什麼?
克隆是非常危險的,如果你是誰抄襲對象有composition.You需要考慮下面這種情況下可能的副作用,因爲克隆創建淺拷貝:
讓說你有一個對象來處理數據庫相關的操作。假設,該對象具有Connection
對象作爲屬性之一。
因此,當有人創建了originalObject
的克隆,正在創建的對象,比如說cloneObject
。 這裏的originalObject
和cloneObject
對於Connection
對象保持相同的參考。
咱們說originalObject
關閉Connection
對象,所以現在cloneObject
將無法工作,因爲connection
對象是他們之間共享,這是actaually由originalObject
關閉。
如果假設您想克隆具有IOStream作爲屬性的對象,則可能會出現類似問題。
如果對象是複合對象,遞歸克隆是如何發生的?
可克隆執行淺拷貝。意思是原始對象和克隆對象的數據將指向相同的參考/內存。 相反,在深拷貝的情況下,原始對象的內存數據被複制到克隆對象的內存中。
相比什麼優點和缺點? – Galactus 2010-11-02 20:37:52
我讀到,這意味着類是克隆與不克隆的優勢。不知道如何解釋:S – allyourcode 2013-05-25 01:50:28