學習effective java-11對所有對象共同的方法之覆寫clone方法時請慎重考慮

該知識點是自己從書籍中學習的筆記。

    Cloneable接口最開始設計目的是打算作爲最小的clone接口,如果對象實現了它的話,那麼就說明該對象具有clone的權限。但是實際上該接口並沒有達到此要求,因爲該接口裏面什麼也沒有。但是Object中有clone方法,並且是protected。

     不能夠因爲一個對象實現了Cloneable接口,就可以通過反射的方式來調用clone方法。即使反射調用也可能會失敗,因爲這裏並不能夠保證每個對象有具有可訪問的clone方法。如果一個類實現了Cloneable,則Object的clone方法就返回該對象的逐域拷貝。

     在子類中調用super.clone()方法獲取到的是該子類的實例。如果在clone方法中通過構造方法來建立一個對象的話,那麼就得不到正確的實例類。因此,如果要重寫一個非final的clone方法時,請在clone方法中調用super.clone來獲取本類的實例。

      一個比較好的clone方法可以調用構造方法來創建對象,構造之後再複製內部數據。如果這個類是final的,clone甚至可以返回一個有構造方法創建的對象。

      從jdk1.5開始,當子類重寫父類的方法時,子類的重寫方法的返回類型可以是父類返回類型的子類類型。這樣做的目的是可以給客戶端提供更多的類的信息以及減少了類型轉換工作。

      實際上,clone方法是另一個構造方法,你必須確保它不會傷害到原始的對象,並且正確地建立起被克隆對象中的約束關係。基本規定:clone結構與指向可變對象的final域的正常用法是不兼容的,除非原始對象和克隆對象之間可以安全地共享此可變對象。爲了能夠使一個類能夠被克隆,請儘量將某個域的final修飾符去掉。遞歸調用clone往往還不夠。

      克隆複雜對象的最後一個辦法是:先調用super.clone,然後把結果對象中的所有域都設置到它們的空白狀態(初始狀態),然後調用高層的方法來重新產生對象的狀態。和構造方法一樣,clone方法不應該在構造過程中調用新對象中任何非final方法,因爲會破壞原始對象和新對象之間的狀態。

Object的clone方法是拋出了CloneNotSupportedException,如果一個類是重寫了這個方法的話,那麼可以不聲明此異常,因爲Public clone方法用起來比有異常更舒服。如果一個類是繼承父類重寫clone方法的話,那麼就應該模仿Object的clone的樣式,將clone聲明成protected,並且拋出異常。

       總之,如果所有實現了Cloneable接口的類,並且都用public重寫了clone方法,返回類型是本類型的話,那麼就需要首先調用super.clone,然後將需要的值一個一個的複製。克隆分爲:深度克隆、淺克隆。如果一個克隆的對象含有可變對象的引用,就需要深度克隆。如果一個克隆對象僅僅包含原始數據類型和不可變對象,則不需要克隆。當然也有些例外,如代表序列號、唯一id、或者代表對象創建時間的域,不管是原始數據還是不可變對象,都需要複製。

       如果你實現了Coneable接口的話,那麼除了實現clone方法外就沒有其他方法了。否則的話,你就必須提供其他途徑來建立對象copy或者就不提供copy方法。

       對於克隆來說,並不一定要克隆。比如說,對於不可變對象,則可以不必進行克隆,因爲它和原始對象沒有任何區別。

       另外一個實現對象拷貝的方法是提供一個拷貝構造方法,該方法僅僅包含一個參數(就是該類的類型參數)。如:

          Public Copy(Copy copy){}

        另外一個就是拷貝構造方法的微型,提供一個工廠方法,如:

           Public static Copy getNewInstance(Copy copy){}

        使用拷貝構造方法或者工廠方法來獲取Clone對象的優勢:不依賴於某一種很有風險、語言之外的對象創建機制;不要遵守尚未良好文檔化的規範;不會與final域的正常使用發生衝突;不會要求客戶捕獲不必要的被檢查異常;爲客戶提供了一個靜態類型化的對象。另外它們都可以帶一個參數,該參數類型可以是接口類型的。例如通用集合實現都提供了一個拷貝構造函數,它們的參數類型都是Collection或Map。基於接口的拷貝構造方法運行客戶來選擇拷貝動作的具體實現,而不強迫客戶接受原始的實現。

         由於Coneable接口有很多的缺陷,建議不要使用它。

發佈了42 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章