對象的複製:淺複製(clone()方法的使用)+深複製

首先需要了解對象深、淺複製的概念:
淺複製:將一個對象複製後,基本數據類型(如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

可以看出,淺複製只複製基本數據類型,對象引用不變,深複製會複製基本數據類型和對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章