Java中的深克隆和淺克隆


為什么要克隆

首先思考一個問題, 為什么需要克隆對象? 直接new一個對象不行嗎?

克隆的對象可能包含一些已經修改過的屬性, 而new出來的對象的屬性都還是初始化時候的值, 所以當需要一個新的對象來保存當前對象的"狀態"時就要靠克隆了.

當然, 把對象的屬性一個一個的賦值給新new的對象也是可以的, 但是這樣一來麻煩不說, 二來, 我們通過源碼查看 Object的clone方法是一個native方法(native方法是非Java語言實現的代碼, 供Java程序調用, 要想訪問比較底層的與操作系統相關的就沒辦法了, 只能由靠近操作系統的語言來實現), 就是快啊, 實在更底層實現的.

我們常見的 Object a = new Object(); Object b; b = a; 這種形式的代碼復制的是引用, 即對象在內存中的地址, a和b指向了同一個對象. 而通過clone方法賦值的對象跟原來的對象是同時獨立存在的.

概念

淺克隆:

被克隆的對象里的所有變量值都與原來的對象相同, 而所有對其他對象的引用仍然指向原來的對象. 簡單說, 淺克隆僅克隆當前對象, 而不克隆當前對象所引用的對象.

深克隆:

被克隆的對象里的所有變量值都與原來的對象相同, 那些引用其他對象的變量將指向被復制過的新對象, 而不再是原來被引用的對象. 簡單說, 深克隆不僅克隆了當前對象, 還把當前對象所引用的對象都復制了一遍.

Object中的clone

Object類中的clone()方法屬於淺克隆. 它的工作原理如下: 在內存中先開辟一塊和原始對象相同的空間, 然后復制原始對象的內容. 對於基本數據類型, 這樣操作當然沒問題, 但對於引用類型, 由於保存的僅僅是對象的引用, 克隆過去的引用所指向的是同一個對象.

Java中實現淺克隆

java中實現clone要實現 Cloneable 接口, 該接口十分簡單, 源碼如下:

Java中的深克隆和淺克隆

 

僅僅起到一個標識的作用.

下面是一個實現淺克隆的例子:

Java中的深克隆和淺克隆

 

可以看到, 對象確實不是原來的對象了, 但是其中的引用對象卻還是原來的對象.

淺克隆對於引用對象僅拷貝引用.

如果一個對象只包含原始數據或者不可變對象域(如: String), 推薦使用淺克隆.

Java中實現深克隆

將類中的所有引用類型都進行clone, 並重寫對象clone()方法, 對所有引用類型進行clone.

代碼如下:

Java中的深克隆和淺克隆

 

將所有引用類型都進行clone, 實現了深克隆.

Java序列化克隆

如果引用類型中海包括引用類型, 要實現多層克隆會很麻煩, 這使用可以使用序列化和反序列化的方式實現對象的深克隆.

把對象寫到字節流中的過程是序列化的過程, 而把對象從字節流中讀出來的過程是反序列化的過程. 由於Java序列化的過程中, 寫在流中的是對象的一個拷貝, 而原對象仍然在JVM中, 所以可以利用這個原理來實現對對象的深克隆.

上面代碼使用序列化實現如下:

Java中的深克隆和淺克隆

 

可以將序列化克隆封裝為一個方法, 如下所示:

Java中的深克隆和淺克隆

 

通過該工具類即可進行深度克隆. 要是用該方法, 對象、對象的所有引用類型、引用類型中的引用類型都要實現 Serializable 接口.


當然, 對象中的final對象是不能進行clone的, 因為final的限制.

如果用線程安全的類實現Cloneable, 要保證它的clone方法做好同步工作, 默認的Object.clone方法是沒有同步的.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM