2015-11-02 70 views
19

我瞭解Java克隆的工作原理以及反對使用它的論點。可以說我無論如何都無法使用它。爲什麼不在內部重寫.clone?

爲方便起見,我想如下編寫類Foo的克隆方法:

@Override 
public Foo clone(){ 
    Foo f = (Foo)super.clone(); 
    //Replace mutable fields 
    return f; 
} 

據我可以告訴這將是安全的。但是,我注意到API中的Cloneable類不這樣做。這是否有一個原因,這是不好的風格?

+1

請注意,這隻有在你像這樣使用它時纔有用:'Foo foo = ...; Foo bar = foo.clone()'。 – biziclop

回答

17

在Java 5之前,協變返回類型根本不被允許,所以Foo clone()甚至不會編譯。 由於許多Cloneable類已經寫了很久以前,這可能是大多數情況下的原因。

我懷疑新的類不使用它,只是因爲clone()被認爲是相當少數,當人們很少使用它時,他們甚至不認爲他們可以施放它。他們發現了一些「如何實現clone()」的問題,並以舊式的方式編寫代碼。

+5

好老「這是如此破產從來沒有人甚至試圖浪費時間試圖解決它」。 – mgarciaisaia

3

Object.clone()創建一個新對象,其中所有字段的值都與原始值相同。對於引用類型的字段,這意味着新字段僅僅是對原始對象的引用。它沒有clone字段。因此,在很多情況下,默認實現會導致共享數據,這可能是不可取的。例如,如果ArrayList.clone()使用默認實現,則最終將有兩個共享相同的後備陣列的ArrayList實例。

如果對象的所有字段都是不可變的,那麼簡單地將super.clone()的結果轉換爲適當的類型可能是個好主意。

+1

API對於克隆(clone)的作用是非常模糊的,但它確實會這麼說:「通常,這意味着複製包含被克隆對象的內部」深層結構「的任何可變對象,並將引用替換爲這些對象引用了這些副本,所以'clone()'應該返回一個深層副本。理想但不一定...... – biziclop

+0

如果這些字段都是不可變的,那麼深度和淺度拷貝之間沒有區別。 –

+3

這是真的,但這與問題有關嗎?我有點失落。 :) – biziclop

3

嗯,這絕對不是實際上它的最好一個壞的風格,你這樣做,因爲Java 1.5的發佈,因爲協變返回類型爲 在1.5版引入了泛型的一部分,並通過這樣做,你是使您的API更易於使用(不需要投射)。 (有效的Java第2版)。

相關問題