1. 程式人生 > >java基礎知識總結--物件的克隆

java基礎知識總結--物件的克隆

前提:在Java語言中所有的類的都是預設的繼承Java語言中的Object類的,

protected native Object clone() throws CloneNotSupportedException;

它還是一個native的方法,大家都知道native的方法是非Java語言實現的程式碼,供Java語言呼叫,因為Java程式是執行在虛擬機器上的,要想訪問到比較低層的與作業系統相關的就沒有辦法了,只能由靠近作業系統的語言實現。

每一個物件直接或者間接的繼承Object,因此他們都含有clone()方法,但是這個方法是Protected,所以不能在類外邊訪問。要想實現對一個物件的複製,就需要對clone()方法進行覆蓋。

為什麼要克隆?

     克隆的物件可能包含一些已經修改過的屬性,而new出來的物件都是初始化時候的值,所以當需要一個新的物件儲存當前物件狀態的時候就要靠clone()方法了。那麼如果把這個物件的臨時屬性一個一個的賦值給新new出來的變數就會比較麻煩;而且clone()方法是非Java語言實現的更接近低層,所以速度比較快。

注意:我們常見的Object a=new Object();Object b;b=a;這種形式的程式碼複製的是引用,即物件在記憶體中的地址,a和b物件仍然指向了同一個物件。通過clone()方法複製的物件跟原來的物件是同時獨立存在的。

如何實現克隆?

兩種不同的克隆方法:淺克隆(shallowclone)和深克隆(deepclone) 。在Java語言中,資料型別分為基本資料型別和引用型別,其中引用資料型別主要包括類、介面、陣列等複雜的資料型別。淺克隆和深克隆的主要區別在於是否支援引用型別的成員變數的複製。

       一、淺克隆的一般步驟:

  • 被複制的類需要實現Clonable介面。該介面為標記介面,裡邊不含任何的方法。
  • 覆蓋clone()方法,訪問修飾符設為public,方法中呼叫super.clone()方法得到需要的複製物件。

 

  這就是淺克隆,兩個物件引用分別指向的是不同的堆記憶體空間。這裡我們能看到,在學生這個類裡面的所有成員變數都是基本資料型別,所以這個時候使用淺克隆是完全沒有問題的,因為成員變數不涉及到引用資料型別。

二、深克隆的一般步驟:

       深克隆和淺克隆的區別就是在一個類裡邊如果有引用型別的變數的話,依然使用淺克隆的方法進行物件引用的複製,那麼出現的結果就是物件裡的引用型別變數只是變數的複製,實際上並沒有為複製的引用型別變數重新開闢空間。所以,為了達到真正的複製物件,針對引用型別變數不單單是變數的複製,我們需要將引用型別變數可複製化,並且還要修改clone()方法。

Eg:在學生類裡邊加入地址類:

深克隆的一般步驟:

  • 當某一個類A是另一個類B的成員變數的時候,那麼類A也要實現Clonable()這個介面,並且重寫clone()方法。

 

 

  •  類B也要實現Clonable()這個介面,並且在類B的實現程式碼裡邊也要重寫clone()方法。

 

 

淺克隆和深克隆的比較?

1、淺克隆:在前克隆中,如果原型物件的成員變數是值的型別,將複製一份給克隆物件;如果原型物件的成員變數是引用型別,則將引用物件的地址複製一份給克隆物件,也就是說原型物件和克隆物件的成員變數(引用型別)指向相同的記憶體地址。

 

2、深克隆:在深克隆中無論原型物件的成員變數是值型別還是引用型別,都將複製一份給克隆物件,深克隆將原型物件的所有引用物件也複製一份給克隆物件。

簡單地說就是在深克隆中,除了物件本身被複制外,物件所包含的成員變數也將複製。

 

 

注意:如果引用型別裡面還包含很多引用型別,或者內層引用型別的類裡面又包含引用型別,使用clone方法就會很麻煩。這時我們可以用序列化的方式來實現物件的深克隆。