Java在運行時的內存使用分兩塊:棧內存與堆內存。
只就變量而言,棧內存上分配一些基本類型的變量(如int
、boolean
)與對象的引用,而堆內存分配給真正的對象本身以及數組等,堆內存上的數據由棧內存上的相應變量引用,相當於棧中存儲着堆內存中實際對象或數組的標記或別名(實際上是堆內存變量首地址)。
將對象複製出一份的行爲稱爲對象的拷貝。
一般來說,拷貝出的對象需要滿足以下三點:
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x)
首先定義三個類。
PersonalInfo.java
|
|
Manager.java
|
|
Department.java
|
|
當需要被克隆的對象的類沒有實現Cloneable
接口而被調用clone
方法時,就會拋出CloneNotSupportedException
。
再在Main類中編寫測試用的斷言,本文將面向測試一步一步地實現最終的徹底深拷貝。
|
|
爲了使斷言機制工作,我們在運行/調試配置中傳入VM參數-enableassertions
。
主要有兩種約定俗成的形式來實現拷貝,本文選擇clone()
。
clone
方法Object.class
|
|
protected
表示該方法只能在本身、本包以及子類中使用。
new
關鍵字 這種方式與重寫clone()
大同小異,唯一不同的是new
關鍵字直接開闢了新對象,繼而只需要完成相應字段的拷貝工作。
在學習編寫Java代碼的過程中,最常見的問題就是String
的「相等」,以此爲思路,首先嚐試:
|
|
斷言失敗在assert dep0 != dep1;
,說明dep0
和dep1
根本就是引用了堆上的同一個對象,拷貝也就更無從談起了。
同一引用
在沒有顯式重寫Department
類的clone
方法時,嘗試:
|
|
斷言失敗在assert dep0.getManager() != dep1.getManager();
,說明