首先需要了解對象深、淺複製的概念:
淺複製:將一個對象複製後,基本數據類型(如int,String,boolean)的變量都會重新創建,而引用類型,指向的還是原對象(或數組)所指向的。
① 拷貝時候雖然創建了新的對象,但是並沒有調用構造方法,直接複製堆上面的對象
② 對象中的引用對象並沒有拷貝,引用的地址還是和原對象一致
③ 基本類型或者 String 默認會拷貝
深複製:將一個對象複製後,不論是基本數據類型還有引用類型,都是重新創建的。簡單來說,就是深複製進行了完全徹底的複製,而淺複製不徹底。
要實現深複製,需要採用流的形式讀入當前對象的二進制輸入,再寫出二進制數據對應的對象。
實現見原型模式。
·clone()方法的使用
1. 實現Cloneable接口;
2. 重寫clone();
3. 內部調用super.clone();
4. clone()修飾符爲public
public class Prototype implements Cloneable {
public Object clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
}
·**重點內容**Java中如果clone爲什麼必須實現Cloneable接口
1. clone()是native方法,在object中申明如下:
protected native Object clone() throws CloneNotSupportedException;
2. 不實現Cloneable接口,調用clone()時會拋CloneNotSupportedException異常。
3. Cloneable接口只是一個標誌類,用來標識實現該接口的類具有克隆功能
淺複製實現如下:
/* 淺複製 */
public Object clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}
深複製則可以基於Java中的序列化和反序列化實現。
1. 首先要被複制的類要實現Serializable接口,這是一個空接口,作用與Cloneable類似,表明當前類支持序列化和反序列化。
2. 定義並實現深複製方法(方法命名可以隨意取),這裏叫deepClone吧。
public CloneClass deepClone() throws IOException, ClassNotFoundException {
/* 寫入當前對象的二進制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 讀出二進制流產生的新對象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (CloneClass) ois.readObject();
}
代碼實現如下:
/* 深複製 */
public class CloneClass implements Serializable
public Object deepClone() throws IOException, ClassNotFoundException {
/* 寫入當前對象的二進制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 讀出二進制流產生的新對象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
接下來看例子:
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException, CloneNotSupportedException, ClassNotFoundException {
CloneClass cloneClass = new CloneClass();
System.out.println("原對象裏對象引用地址: " + cloneClass.node.toString());
cloneClass.x++;
System.out.println("原對象基本數據類型地址: " + cloneClass.x.toString());
CloneClass shadowClone = cloneClass.clone();
System.out.println("淺複製對象裏對象引用地址: " + shadowClone.node.toString());
shadowClone.x++;
System.out.println("淺複製對象基本數據類型地址: " + shadowClone.x.toString());
CloneClass deepClone = cloneClass.deepClone();
System.out.println("深複製對象裏對象引用地址: " + deepClone.node.toString());
System.out.println("深複製對象基本數據類型地址:" + deepClone.x.toString());
}
}
class CloneClass implements Cloneable, Serializable {
public Integer x = 1;
TreeNode node = new TreeNode(2);
@Override
public CloneClass clone() throws CloneNotSupportedException {
return (CloneClass) super.clone();
}
public CloneClass deepClone() throws IOException, ClassNotFoundException {
/* 寫入當前對象的二進制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 讀出二進制流產生的新對象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (CloneClass) ois.readObject();
}
}
class TreeNode implements Serializable {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
輸出結果:
原對象裏對象引用地址: swordToOffer.TreeNode@2b193f2d
原對象基本數據類型地址: 2
淺複製對象裏對象引用地址: swordToOffer.TreeNode@2b193f2d
淺複製對象基本數據類型地址: 3
深複製對象裏對象引用地址: swordToOffer.TreeNode@1ddc4ec2
深複製對象基本數據類型地址:2
可以看出,淺複製只複製基本數據類型,對象引用不變,深複製會複製基本數據類型和對象。