《Java 核心技术卷1 第10版》学习笔记------对象克隆【对象拷贝】
?由于克隆并不太常見,而且有關的細節技術性很強,你可能只是想稍做了解,等真正需要時再深人學習。
先來回憶為一個包含對象引用的變量建立副本時會發生什么 。原變量和副本都是同一個對象的引用:
Employee original = new Employee ("John Public", 50000); Employee copy = original; // Java 中這叫做引用傳遞,并非 copy/clone copy.raiseSalary(10) ; // oops-also changed original如果希望 copy 是一個新對象, 它的初始狀態與 original 相同 , 但是之后它們各自會有自己不同的狀態, 這種情況下就可以使用 clone 方法 。
Employee copy = original.clone(); // 克隆,實際上不能直接使用這個方法,詳情見下 copy.raiseSalary(10); / / OK original unchanged不過并沒有這么簡單 。clone 方法是 Object 的一個 protected 方法 , 這說明你的代碼不能直接調用這個方法 【搞不懂為什么的請參看:?https://blog.csdn.net/gulang03/article/details/86728054】。 只有 Employee 類可以克隆 Employee 對象 【即 Employee copy = original.clone(); 這種代碼只能出現在 Employee 類內部,除非實現 ?Cloneable 接口,詳情往下看】。
這個限制是有原因的 。 想想看 Object 類如何實現 clone 。 它對于這個對象一無所知 , 所以只能逐個域地進行拷貝 。 如果對象中的所有數據域都是數值或其他基本類型, 拷貝這些域沒有任何問題 、 但是如果對象包含子對象的引用, 拷貝域就會得到相同子對象的另一個引用, 這樣一來, 原對象和克隆的對象仍然會共享一些信息【即:默認的克隆操作是 “ 淺拷貝 ” , 并沒有克隆對象中引用的其他對象 ?!?。
淺拷貝會有什么影響嗎 ?
這要看具體情況 。 如果原對象和淺克隆對象共享的子對象是不可變的 , 那么這種共享就是安全的 。 如果子對象屬于一個不可變的類, 如 String , 就是這種情況 。 或者在對象的生命期中, 子對象一直包含不變的常量 , 沒有更改器方法會改變它, 也沒有方法會生成它的引用, 這種情況下同樣是安全的 。
不過 , 通常子對象都是可變的, 必須重新定義 clone 方法來建立一個深拷貝 , 同時克隆所有子對象 。 在這個例子中, hireDay 域是一個 Date , 這是可變的 , 所以它也需要克隆 。 (出于這個原因 , 這個例子使用 Date 類型的域而不是 LocalDate 來展示克隆過程 。 如果 hireDay是不可變的 LocalDate 類的一個實例, 就無需我們做任何處理了 。)
對于每一個類, 需要確定 :
1 ) 默 認 的 clone 方法是否滿足要求 ;
2 ) 是否可以在可變的子對象上調用 clone 來修補默認的 clone 方法 ;
3 ) 是否不該使用 clone。
實際上第 3 個選項是默認選項 。 如果選擇第 1 項或第 2 項, 類必須:
1 ) 實現 Cloneable 接口 ;
2 ) 重新定義 clone 方法, 并指定 public 訪問修飾符 ?!緸榱?clone() 方法能在任何地方都能使用】
關于 Cloneable 接口的說明:
Cloneable 接口只是一個標記接口(tagging interface),是Java提供的一組標記接口之一。標記接口用途是確保一個類實現一個或一組特定的方法。?標記接口不包含任何方法; 它唯一的作用就是允許在類型查詢中使用 instanceof:
if ( obj instanceof Cloneable)...Cloneable 接口源代碼:
public interface Cloneable { } // 沒有任何待實現的方法即使 clone 的默認 (淺拷貝 ) 實現能夠滿足要求 , 還是需要實現 Cloneable 接口 , 將 clone重新定義為 public , 再調用 super . clone() 。
class Employee implements Cloneable{public Employee clone() throws CloneNotSupportedException {return (Employee) super.clone();} }與 Object.clone 提供的淺拷貝相比 , 前面看到的 clone 方法并沒有為它增加任何功能 。 這里只是讓這個方法是公有的 。 要建立深拷貝 , 還需要做更多工作, 克隆對象中可變的實例域 。
下面來看創建深拷貝的 clone 方法的一個例子 :
class Employee implements Cloneable{...// 注意訪問修飾符改為 publicpublic Employee clone() throws CloneNotSupportedException{// call Object.clone() 完成不可變字段的拷貝Employee cloned = (Employee) super.clone();// clone mutable fileds 完成可變字段的拷貝cloned.hiredDay = (Date) hireDay.clone();return cloned;} }必須當心子類的克隆 。 例如, 一旦為 Employee 類定義了 clone 方法, 任何人都可以用它來克隆 Manager【PS:Manager 是 Employee 類的一個子類】對象 。 Employee 克隆方法能完成工作嗎 ? 這取決于 Manager 類的域 。 在這里是沒有問題的, 因為 bonus 域是基本類型 。 但是 Manager 可能會有需要深拷貝或不可克隆的域 。 不能保證子類的實現者一定會修正 clone 方法讓它正常工作 。 出于這個原因, 在 Object 類中 clone 方法聲明為 protected 。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的《Java 核心技术卷1 第10版》学习笔记------对象克隆【对象拷贝】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《Java 核心技术卷1 第10版》学习
- 下一篇: JMS (Java消息服务) 入门教程