Java Clone

更多 Java 高級(jí)知識(shí)方面的文章,請(qǐng)參見(jiàn)文集《Java 高級(jí)知識(shí)》


首先看下面這一段代碼:

Student s = new Student();
Student s1= s;
  • 如果是在 C++ 中,會(huì)調(diào)用拷貝構(gòu)造函數(shù),復(fù)制一份新的對(duì)象,由 s1 指向該新的對(duì)象
  • 如果是在 Java 中,s1 為引用,仍然指向 s 的內(nèi)存區(qū)域,即同一份對(duì)象

在下面的代碼中:
c1c2 剛開(kāi)始分別指向兩個(gè)不同的對(duì)象,c2 = c1; 使得 c2 指向 c1 的對(duì)象,因此 c2 原本指向的對(duì)象 B 失去引用,會(huì)被 GC 回收。

public class Clone_Test {
    public static void main(String[] args) {
        MyClone c1 = new MyClone("A");
        MyClone c2 = new MyClone("B");

        // c2 指向 c1 的對(duì)象
        // c2 原本指向的對(duì)象 B 失去引用,會(huì)被 GC 回收
        c2 = c1;
        c2.name = "C";

        System.out.println(c1.name); // 輸出 C
        System.out.println(c2.name); // 輸出 C
    }
}

class MyClone {
    public String name;

    public MyClone(String name) {
        this.name = name;
    }
}

Clone 的實(shí)現(xiàn)

實(shí)現(xiàn) Cloneable 接口,并重寫(xiě) clone() 方法。

關(guān)于 Cloneable 接口

  • Cloneable 是一個(gè)空接口。并不包含任何方法,更像是一個(gè)標(biāo)記。
public interface Cloneable {
}
  • implements Cloneable 指示調(diào)用 clone() 方法時(shí)可以合法地對(duì)該對(duì)象進(jìn)行按字段的復(fù)制

A class implements the <code>Cloneable</code> interface to indicate to the clone() method that it is legal for that method to make a field-for-field copy of instances of that class.

  • 如果不實(shí)現(xiàn) Cloneable 接口,此時(shí)在調(diào)用clone() 方法時(shí),會(huì)拋出異常 CloneNotSupportedException

關(guān)于 Clone 方法

  • clone() 方法是 Object 類(lèi)中自帶的 native 方法,參見(jiàn) Java Object 類(lèi)中有哪些方法
  • clone() 方法默認(rèn)是淺復(fù)制
    • 對(duì)基礎(chǔ)類(lèi)型有用
    • 對(duì)引用類(lèi)型只是復(fù)制引用,不是真正地復(fù)制對(duì)象
  • clone() 方法不會(huì)調(diào)用構(gòu)造方法
  • 幾個(gè)基本的比較:
x.clone() == x // false,因?yàn)閯?chuàng)建出了一個(gè)新對(duì)象
x.clone().getClass() == x.getClass() // true
x.clone().equals(x) // 一般為false,取決于 clone() 方法的具體實(shí)現(xiàn)

例如將上述的代碼重構(gòu)為:

public class Clone_Test {
    public static void main(String[] args) {
        MyClone c1 = new MyClone("A");
        MyClone c2 = new MyClone("B");

        // c2 指向一個(gè)新對(duì)象
        // c2 原本指向的對(duì)象 B 失去引用,會(huì)被 GC 回收
        c2 = (MyClone) c1.clone();
        c2.name = "C";

        System.out.println(c1.name); // 輸出 A
        System.out.println(c2.name); // 輸出 C
    }
}

class MyClone implements Cloneable {
    public String name;

    public MyClone(String name) {
        this.name = name;
    }

    public Object clone() {
        MyClone c = null;

        try {
            c = (MyClone) super.clone();
        } catch (Exception e) {
        }

        return c;
    }
}

淺拷貝 VS 深拷貝

Object 類(lèi)中自帶的clone() 方法是淺拷貝,即 field-for-field copy。
如果某個(gè)對(duì)象中包含一些其他對(duì)象,例如 Stream,淺拷貝只會(huì)復(fù)制該 Stream 對(duì)象的引用,該 Stream 對(duì)象會(huì)被兩個(gè)對(duì)象 c1c2 共享,可能會(huì)導(dǎo)致問(wèn)題。

要想實(shí)現(xiàn)深拷貝,即對(duì)象中包含的其他對(duì)象也會(huì)復(fù)制出一份新的對(duì)象,可以通過(guò)如下方式:

  • 需要重寫(xiě) clone() 方法,實(shí)現(xiàn)深拷貝
  • 通過(guò)序列化方式 ObjectOutputStream ObjectInputStream
  • 通過(guò)第三方庫(kù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 在java中,如果需要有拷貝問(wèn)題,都會(huì)使用到父類(lèi)Object的Clone方法,能夠?yàn)槲覀兲峁?duì)象的拷貝方法,在使用...
    三木仔閱讀 1,537評(píng)論 0 2
  • Java Clone 平時(shí)項(xiàng)目中用的也不多,今天來(lái)實(shí)踐下Java的Clone。Clone主要分為“淺拷貝”與“深拷...
    昵稱(chēng)全尼馬被注冊(cè)了閱讀 753評(píng)論 0 3
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,767評(píng)論 18 399
  • 11.Override clone judiciously 大意為 明智地重寫(xiě)clone方法 說(shuō)到clone方法,...
    Mezereon閱讀 815評(píng)論 0 3
  • java筆記第一天 == 和 equals ==比較的比較的是兩個(gè)變量的值是否相等,對(duì)于引用型變量表示的是兩個(gè)變量...
    jmychou閱讀 1,518評(píng)論 0 3