2012-07-25 22 views
1

我讀了有效的Java書,並且不明白在哪一段中解釋了Clonable接口。有人可以解釋我這一段:有效的Java。 Clonable接口

...程序員認爲,只要擴展類和子類調用 super.clone,返回的對象將是子類的實例 。超類可以提供此功能的唯一方法是返回通過調用super.clone獲得的對象。 如果一個克隆方法返回一個由構造函數創建的對象,它將會有 錯誤的類。

謝謝。

+0

就我而言,你不應該使用克隆,你最好用複製構造函數。至於那張克隆看這裏:http://stackoverflow.com/questions/2326758/how-to-properly-override-clone-method – mihaisimi 2012-07-25 16:20:27

+1

還涉及:http://stackoverflow.com/questions/11540792/effective-java - 克隆分析方法 – assylias 2012-07-25 16:22:58

+1

@mihaisimi拷貝構造函數不允許運行時動態類型克隆。例如,請克隆'List list',List list實現的構造函數是你要使用的'ArrayList','LinkedList'? – 2012-07-25 16:32:36

回答

5

我應該注意到在其本身與clone開始被打破,一個拷貝構造函數,像Sheep(Sheep cloneMe)是一個更優雅的成語比clone,考慮到Cloneable合同是非常弱的。你可能已經知道這一點,因爲你正在讀這本書,但值得放在這裏。

總之,要回答這個問題:

Object.clone()將創建同一類型,因爲它被稱爲對對象的對象。出於這個原因,強烈建議「級聯」到Object以獲得您計劃返回的結果。如果有人決定不遵循這個約定,你最終會得到一個違反約定的類型對象,這會導致許多問題。

爲了說明我有像這樣

class Sheep implements Cloneable { 

    Sheep(String name)... 

    public Object clone() { 
     return new Sheep(this.name); // bad, doesn't cascade up to Object 
    } 
} 

class WoolySheep extends Sheep { 

    public Object clone() { 
     return super.clone(); 
    } 
} 

類突然,如果我做

WoolySheep dolly = new WoolySheep("Dolly"); 
WoolySheep clone = (WoolySheep)(dolly.clone()); // error 

,因爲我從dolly.clone()回去我會得到一個例外是Sheep,而不是WoolySheep

+0

現在你有它。 – jtahlborn 2012-07-25 16:28:08

+0

@jtahlborn它假定,正如問題所述,「Sheep.clone()」是用給定的構造函數不恰當地實現的。我已經編輯它來明確。 – corsiKa 2012-07-25 16:28:32

+0

重要的是'克隆'是不道德的:-) – corsiKa 2012-07-25 16:29:42

1
class A { 
    protected Object clone() { 
     return new A(); 
    } 
} 

class B extends A implements Cloneable { 
    public Object clone() { 
     return super.clone(); 
    } 
} 

這裏,A具有無效實現clone因爲這將拋出一個異常:

B obj = (B)(new B()).clone(); 

相反,A.clone()必須調用super.clone(),而不是一個構造函數。 Object.clone()將生成運行時類型的新對象,而不是編譯時類型。

任何字段然後克隆到這個新的對象。如果你已經有了一個初始化你的所有字段的構造函數(比如複製構造函數),那麼它會很誘人,但是這會導致任何子類的行爲不正確。

如果該類是final,那麼它並不重要,因爲它不能有任何子類。

+0

然後在這裏看到如何克隆是如何破碎和混淆:http://www.artima.com/intv/issues3.html – OrangeDog 2012-07-25 16:34:31

1

我不同意@ corsiKa的回答。自Java5.0以來。Java支持協變返回類型,因此,對於克隆的正確實施()應該是:

class Sheep implements Cloneable { 

    Sheep(String name)... 

    public Sheep clone() { 
     return new Sheep(this.name); 
    } 
} 

class WoolySheep extends Sheep { 

    public WoolySheep clone() { 
     return super.clone(); // compile time error, Type miss match. 
    } 
} 

而且該建議的替代拷貝構造函數不支持多態。考慮下面的例子(哪個複製構造函數不能做):

interface Animal implements Cloneable { 
    String whatAreYou() 
} 

class Cat implements Animal { 
    String whatAreYou() { 
    return "I am a cat"; 
    } 
    Cat clone() { 
    return new Cat(); 
    } 
} 

class Dog implements Animal{ 
    String whatAreYou() { 
    return "I am a dog"; 
    } 
    Dog clone() { 
    return new Dog(); 
    } 
} 

class Lib { 
    Animal cloneAnimal(Animal animal) { 
    return animal.clone(); 
    } 
}