為了實現克隆,我們需要配置我們的類并遵循以下步驟:
在我們的類或其超類或接口中實現 Cloneable 接口。
定義一個應處理 CloneNotSupportedException(拋出或記錄)的 clone() 方法。
并且,在大多數情況下,我們從clone()方法中調用超類的clone()方法。
Java 克隆與復制構造函數
super.clone() 將調用它的 super.clone(),并且鏈將繼續,直到調用到達 Object 類的 clone() 方法,該方法將創建一個字段到我們對象的字段 mem 副本并將其返回。
與一切事物一樣,克隆也有其優點和缺點。然而,Java 克隆因其設計問題而聞名,但它仍然是當今最常見和流行的克隆策略。
Object.clone() 的優點
正如前面提到的,Object.clone() 存在許多設計問題,但它仍然是最流行和最簡單的復制對象的方法。使用clone()的一些優點是:
克隆需要的代碼行少得多——只需一個具有 4 行或 5 行長的 clone() 方法的抽象類,但如果我們需要深度克隆,我們將需要重寫它。
這是復制對象的最簡單方法,特別是當我們將其應用于已經開發的或舊的項目時。我們只需要定義一個父類,在其中實現 Cloneable,提供clone() 方法的定義,就可以了。我們父母的每個孩子都將獲得克隆功能。?
我們應該使用克隆來復制數組,因為這通常是最快的方法。
從版本 1.5 開始,在數組上調用克隆會返回一個數組,其編譯時類型與被克隆的數組的編譯時類型相同,這顯然意味著在數組上調用克隆不需要類型轉換。
Object.clone() 的缺點
以下是導致許多開發人員不使用 Object.clone() 的一些缺點:
使用 Object.clone() 方法需要我們在代碼中添加大量語法,例如實現 Cloneable 接口、定義 Clone() 方法并處理 CloneNotSupportedException,最后調用 Object.clone() 并將其強制轉換到我們的對象上。
Cloneable 接口缺少clone() 方法。實際上,Cloneable是一個標記接口,里面沒有任何方法,我們仍然需要實現它只是為了告訴JVM我們可以對我們的對象執行clone()。
Object.clone() 是受保護的,因此我們必須提供自己的clone() 并從中間接調用Object.clone()。
我們無法控制對象構造,因為 Object.clone() 不會調用任何構造函數。
如果我們在子類(例如Person)中編寫clone方法,那么它的所有超類都應該在其中定義clone()方法或從另一個父類繼承它。否則, super.clone() 鏈將會失敗。
Object.clone() 僅支持淺復制,因此新克隆的對象的引用字段仍將保留原始對象的字段所保留的對象。為了克服這個問題,我們需要在我們的類持有引用的每個類中實現clone(),然后在我們的clone()方法中單獨調用它們的克隆,如下例所示。
我們無法在 Object.clone() 中操作 Final 字段,因為 Final 字段只能通過構造函數更改。在我們的例子中,如果我們希望每個 Person 對象的 id 都是唯一的,那么如果使用 Object.clone(),我們將得到重復的對象,因為 Object.clone() 不會調用構造函數,并且最終的 id 字段不能修改自 Person.clone()。