2008-11-06 76 views
14

一位同事最近問我如何深度克隆一個Map,並且我意識到我可能從來沒有使用clone()方法 - 這讓我很擔心。你用Object.clone()做了什麼?

在您需要克隆對象的地方,您發現了哪些最常見的場景?

回答

15

我假定您指的是Java中的Object.clone()。如果是,請注意Object.clone()存在一些主要問題,並且在大多數情況下不鼓勵使用它。請參閱Joshua Bloch的"Effective Java"中的項目11獲取完整答案。我相信您可以在原始類型數組上安全使用Object.clone(),但除此之外,您需要明智地正確使用和覆蓋克隆。你最好定義一個拷貝構造函數或一個靜態工廠方法,根據你的語義顯式地克隆這個對象。

5

最常見的情況是,當我不得不將一個可變對象返回給調用者時,我擔心調用者可能會使用這種調用方法,而且往往以線程不友好的方式。列表和日期是我爲此做的最多的。如果調用者可能想遍歷一個List,並且有線程可能更新它,則返回它的一個克隆或副本會更安全。

其實,這提出了一些我將不得不打開另一個問題:複製構造函數或克隆?當我做C++的時候,我們總是做了一個拷貝構造函數並實現了它的克隆,但是如果你使用拷貝構造函數來實現你的克隆,FindBugs不會喜歡它。

+0

如果您使用複製構造函數來實現clone(),而不是調用super.clone(),那麼當某人對您的類進行子類分類並調用clone時,它們將獲得超類類型的對象,而不是子類類型。 – 2008-11-06 23:42:55

+0

@丹,是的,這幾乎是FindBugs所說的。剛剛閱讀了一些從StackOverflow的答案鏈接到關於C++的問題後,我現在可以明白,在C++中這樣做並不是很好。 – 2008-11-07 03:22:02

3

當我需要複製某些內容以修改重複內容而不影響原始內容時,當然在這種情況下,只需要進行深度克隆即可。我必須在一個系統上執行此操作,在該系統中,我將克隆域類實例,應用用戶的更改,然後對兩者進行比較以供用戶驗證其更改。

2

Object.clone()方法不指定子類的副本是深層還是淺層副本,它完全依賴於特定的類。 Object.clone()方法本身做一個淺拷貝(拷貝Object類的內部狀態),但是子類必須覆蓋它,調用super.clone(),並根據需要拷貝它們的內部狀態(淺或深)。

它確實規定了一些約定,你可能不遵守。對於(a.getClass()== a.clone()。getClass())返回true,應該調用super.clone()而不是簡單的'new Subclass()',因爲super.clone()可能會正確實例化此對象的類(即使在子類中),並複製包含專用字段的所有內部狀態,這些狀態不能由子類使用複製構造函數應付可見性規則複製。或者你將被迫公開一個不應該暴露的構造函數,以便更好地封裝。

實施例:

//simple clone 
class A implements Cloneable { 
    private int value; 
    public A clone() { 
    try { 
     A copy = (A) super.clone(); 
     copy.value = this.value; 
     return copy; 
    } catch (CloneNotSupportedException ex) {} 
    } 
} 

//clone with deep and shallow copying 
class B extends A { 
    Calendar date; 
    Date date; 
    public B clone() { 
    B copy = (B) super.clone(); 
    copy.date = (Calendar) this.date.clone(); // clones the object 
    copy.date = this.date; // copies the reference 
    return copy; 
    } 
} 

深拷貝通常用於當從屬於對象是可變(例如日曆),並且複製必須完全獨立於原始的。

當從屬對象是不可變的(如Date)時,共享相同的實例通常不是問題,並且淺拷貝可能就足夠了。

使用Object.clone()時,您必須遵循一些規則,但它們很簡單,可以理解。可能最困難的部分是正確定義你應該複製到對象圖表中的深度。一個邏輯問題,而不是語言問題,即。

0

我已經使用了Object。克隆()在Spring Webflow應用程序中檢查用戶在表單上編輯/輸入數據以進行審計時發生了什麼變化。

在流程開始時,我調用在Spring Webflow中使用的窗體支持對象上實現的克隆方法,並將克隆的實例保存到用戶會話中。一旦用戶在html表單上完成編輯數據並按下保存按鈕,我將綁定到後備對象的新值與克隆值進行比較,以確定用戶已更改的數據。

這工作得很好,很容易實現,我沒有真正遇到任何與Java克隆有關的問題。