Java 中的淺拷貝與深拷貝

Java 中的淺拷貝與深拷貝

[toc]

參考:Java 中的淺拷貝與深拷貝
詳細(xì)源碼介紹和示例看:JavaSE學(xué)習(xí)隨筆(一) Cloneable接口源碼分析與技術(shù)細(xì)節(jié)

總結(jié):

java中clone方法是淺拷貝
實現(xiàn)Clonable接口,重寫clone方法的是深拷貝

基本數(shù)據(jù)類型:直接拷貝
對象類型:引用拷貝、對象拷貝
深拷貝和淺拷貝都是對象拷貝

詳情

什么是拷貝?

引用拷貝:
正如它的名稱所表述的意思, 就是創(chuàng)建一個指向?qū)ο蟮囊米兞康目截?。如果我們有一個 Car 對象,而且讓 myCar 變量指向這個變量,這時候當(dāng)我們做引用拷貝,那么現(xiàn)在就會有兩個 myCar 變量,但是對象仍然只存在一個。


引用拷貝

對象拷貝:
會創(chuàng)建對象本身的一個副本。因此如果我們再一次服務(wù)我們 car 對象,就會創(chuàng)建這個對象本身的一個副本, 同時還會有第二個引用變量指向這個被復(fù)制出來的對象。

對象拷貝

備注:深拷貝和淺拷貝都是對象拷貝

淺拷貝

首先讓我們來說說淺拷貝。對象的淺拷貝會對“主”對象進(jìn)行拷貝,但不會復(fù)制主對象里面的對象。"里面的對象“會在原來的對象和它的副本之間共享。例如,我們會為一個 Person對象創(chuàng)建第二個 Person 對象, 而兩個 Person 會共享相同的 Name 和 Address 對象。


淺拷貝

在一下示例 中,我們有一個類 Person,類里面包含了一個 Name 和 Address 對象??截悩?gòu)造器會拿到 originalPerson 對象,然后對其應(yīng)用變量進(jìn)行復(fù)制。

public class Person {
    private Name name;
    private Address address;

    public Person(Person originalPerson) {
         this.name = originalPerson.name;
         this.address = originalPerson.address;
    }
[…]
}

淺拷貝的問題就是兩個對象并非獨立的。如果你修改了其中一個 Person 對象的 Name 對象,那么這次修改也會影響奧另外一個 Person 對象。

讓我們在示例中看看這個問題。假如說我們有一個 Person 對象,然后也會有一個引用變量 monther 來指向它;然后當(dāng)我們對 mother 進(jìn)行拷貝時,創(chuàng)建第二個 Person 對象 son。如果在此后的代碼中, son 嘗試用 moveOut() 來修改他的 Address 對象, 那么 mother 也會跟著他一起搬走!

Person mother = new Person(new Name(…), new Address(…));
[…]
Person son  = new Person(mother);
[…]
son.moveOut(new Street(…), new City(…));

這種現(xiàn)象之所以會發(fā)生,是因為 mother 和son 對象共享了相同的 Address 對象,如你在示例中所看到的描述。當(dāng)我們在一個對象中修改了 Address 對象,那么也就表示兩個對象總的 Address 都被修改了。

深拷貝

不同于淺拷貝,深拷貝是一個整個獨立的對象拷貝。如果我們對整個 Person對象進(jìn)行深拷貝,我們會對整個對象的結(jié)構(gòu)都進(jìn)行拷貝。


深拷貝

如上圖所見,對一個 Person 的Address對象進(jìn)行了修改并不會對另外一個對象造成影響。當(dāng)我們觀察示如下代碼,會發(fā)現(xiàn)我們不單單對 Person 對象使用了拷貝構(gòu)造器,同時也會對里面的對象使用拷貝構(gòu)造器。

public class Person {
    private Name name;
    private Address address;

    public Person(Person otherPerson) {
         this.name    =  new Name(otherPerson.name);
         this.address =  new Address(otherPerson.address);
    }
[…]
}

使用這種深拷貝,我們可以重新嘗試之前的示例中的 mother-son 這個用例?,F(xiàn)在 son 可以成功的搬走了!

不過,故事到這兒并沒有結(jié)束。要創(chuàng)建一個真正的深拷貝,就需要我們一直這樣拷貝下去,一直覆蓋到 Person 對象所有的內(nèi)部元素, 最后只剩下原始的類型以及“不可變對象(Immutables)”。讓我們觀察下如下這個 Street 類以獲得更好的理解:

public class Street {
    private String name;
    private int number;

    public Street(Street otherStreet){
         this.name = otherStreet.name;
         this.number = otherStreet.number;
    }
[…]
}

Street 對象有兩個實體變量組成 – String 類型的 name 以及 int 類型的 number。int 類型的 number 是一個原始類型,并非對象。它只是一個簡單的值,不能共享, 因此在創(chuàng)建第二個實體變量時,我們可以自動創(chuàng)建一個獨立的拷貝。String 是一個不可變對象(Immutable)。簡言之,不可變對象也是對象,可一旦創(chuàng)建好了以后就再也不能被修改了。因此,你可以不用為其創(chuàng)建深拷貝就能對其進(jìn)行共享。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容