首頁 > 軟體

詳解Java深拷貝,淺拷貝和Cloneable介面

2022-08-21 18:00:11

1. Cloneable介面的介紹

Cloneable是標記型的介面(空介面),它們內部都沒有方法和屬性,實現 Cloneable來表示該物件能被克隆,能使用Object.clone()方法。如果沒有實現 Cloneable的類物件呼叫clone()就會丟擲CloneNotSupportedException異常。

可以理解為Cloneable介面發揮的是標記功能,自定義型別需要使用者自己標記出哪些類是可以clone的,這個標記就是去實現Cloneable介面,實現了Cloneable介面後就表明該類建立的物件可以被克隆。

而要想使一個類具備拷貝範例的功能,除了要實現Cloneable介面,還必須重寫Object類的clone()方法。

可以看到Object類的clone()方法是被protected修飾的,所以需要在重寫的clone()方法中通過super關鍵字去呼叫Object類中的clone()方法

2. 淺拷貝的介紹和範例

在拷貝一個物件時,對 物件的基本資料型別的成員變數進行拷貝,但對參照型別的成員變數只進行參照的傳遞,並沒有建立一個新的物件,當對參照型別的內容修改會影響被拷貝的物件。簡而言之:淺拷貝僅僅複製所拷貝的物件,而不復制它所參照的物件。

觀察下面的程式碼,將Money類的範例作為了Person類的欄位,new一個Person類的物件person1,將這個person1物件拷貝到person2中,這裡的拷貝就是淺拷貝了,只是將person1物件的money參照拷貝到了person2,person1和person2中的momey指向的是同一個物件。

class Money {
    public double m = 666;
}
class Person implements Cloneable{
    int id;
    public Money money = new Money();

    public Person(int id) {
        this.id = id;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", money=" + money.m +
                '}';
    }
}
public class TestDemo3 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person(1);
        Person person2 = (Person) person1.clone();

        System.out.println("通過person2修改前的結果");
        System.out.println(person1);
        System.out.println(person2);

        person2.money.m = 888;
        person2.id = 2;
        System.out.println("通過person2修改後的結果");
        System.out.println(person1);
        System.out.println(person2);
    }
}

執行結果:

淺拷貝圖解:

3. 深拷貝的介紹和範例

在拷貝一個物件時,除了對基本資料型別的成員變數進行拷貝,對參照型別的成員變數進行拷貝時,建立一個新的物件來儲存參照型別的成員變數。簡而言之:深拷貝把要複製的物件所參照的物件都複製了一遍。

下面的程式碼實現了深拷貝;實現person1物件的深拷貝,先用Person tmp參照來儲存淺拷貝的結果,通過tmp參照找到money物件,再將money物件拷貝一份,然後賦值給tmp中的money,最後返回tmp即可。這樣就將money參照的物件也拷貝了一份,實現了深拷貝,此時person1和person2中的momey指向的是兩個不同的物件。

class Money implements Cloneable{
    public double m = 666;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

class Person implements Cloneable{
    public int id;
    public Money money = new Money();

    public Person(int id) {
        this.id = id;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //return super.clone();
        Person tmp = (Person) super.clone();
        tmp.money = (Money) this.money.clone();
        return tmp;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", money=" + money.m +
                '}';
    }
}
public class Test2 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1 = new Person(1);
        Person person2 = (Person) person1.clone();

        System.out.println("通過person2修改前的結果");
        System.out.println(person1);
        System.out.println(person2);

        person2.money.m = 888;
        person2.id = 2;
        System.out.println("通過person2修改後的結果");
        System.out.println(person1);
        System.out.println(person2);
    }
}

執行結果:

深拷貝圖解:

4. clone方法總結

java中clone方法是一個淺拷貝,參照型別依然在傳遞參照。我們可以通過繼續呼叫clone()方法,對 該物件的參照型別變數再實現一次clone()的方法來實現深拷貝。

到此這篇關於詳解Java深拷貝,淺拷貝和Cloneable介面的文章就介紹到這了,更多相關Java Cloneable介面內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com