淺談 Java 淺拷貝&深拷貝

深拷貝和淺拷貝的概念,我自己在學習Java的時候也沒注意,雖然Java中對象回收工作由GC幫我們做了,但在碼代碼時如果不注意也會埋下隱藏的BUG,今天我們深入探究一下深拷貝和淺拷貝。

我們在寫代碼時經常會需要將一個對象傳遞給另一個對象,Java語言中對于基本型變量采用的是值傳遞,而對于非基本類型對象傳遞時采用的引用傳遞也就是地址傳遞,而很多時候對于非基本類型對象傳遞我們也希望能夠象值傳遞一樣,使得傳遞之前和之后有不同的內存地址。在兩種情況就是我們今天要討論的 淺拷貝深拷貝

有Java基礎的同學可能發現上面論述有些不嚴謹,String 類型在傳遞時其實也是值傳遞,因為 String 類型是不可變對象。

淺拷貝

被復制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺復制僅僅復制所考慮的對象,而不復制它所引用的對象。

下面我們看一個例子:

public class Book implements Cloneable {
    String bookName;
    double price;
    Person author;

    public Book(String bn, double price, Person author) {
        bookName = bn;
        this.price = price;
        this.author = author;
    }

    public Object clone() {
        Book b = null;
        try {
            b = (Book) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return b;
    }

    public static void main(String args[]) {
        Person p = new Person("Dream", 34);
        Book book1 = new Book("Java開發", 30.00, p);
        Book book2 = (Book) b1.clone();
        book2.price = 44.00;
        book2.author.setAge(45);
        book2.author.setName("Fish");
        book2.bookName = "Android開發";
        System.out.print("age = " + book1.author.getAge() + "  name = " 
        + book1.bookName + "     price = " + book1.price);
        System.out.println();
        System.out.print("age = " + book2.author.getAge() + "  name = " 
        + book2.bookName + "     price = " + book2.price);
    }
}

結果:

age = 45 name = Java開發 price = 30.0

age = 45 name = Android開發 price = 44.0

從結果中發現在改變 book2 對象的 name 和 price 屬性時 book1 的屬性并不會跟隨改變,當改變 book2 對象的 author 屬性時 book1 的 author 對象的屬性也改變了,說明 author 是淺拷貝,和 book1 的 author 是使用同一引用。這時我們就需要使用深拷貝了。

深拷貝

被復制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量將指向被復制過的新對象,而不再是原有的那些被引用的對象。換言之,深復制把要復制的對象所引用的對象都復制了一遍。

為了解決上面 Person 對象未完全拷貝問題,我們需要用到深拷貝,其實很簡單在拷貝book對象的時候加入如下語句:

b.author =(Person)author.clone(); //將Person對象進行拷貝,Person對象需進行了拷貝

結果

age = 34 name = Java開發 price = 30.0

age = 45 name = Android開發 price = 44.0

上面是用 clone() 方法實現深拷貝,傳統重載clone()方法,但當類中有很多引用時,比較麻煩。 當然我們還有一種深拷貝方法,就是將對象 序列化 。

把對象寫到流里的過程是序列化(Serilization)過程;而把對象從流中讀出來的反序列化(Deserialization)過程。應當指出的是,寫在流里的是對象的一個拷貝,而原對象仍然存在于JVM里面。

在Java語言里深復制一個對象,常??梢韵仁箤ο髮崿FSerializable接口,然后把對象(實際上只是對象的一個拷貝)寫到一個流里,再從流里讀出來,便可以重建對象。

還是上面的例子,我們重寫 clone() 方法:

public Object deepClone() throws IOException, OptionalDataException, ClassNotFoundException {
    // 將對象寫到流里
    OutputStream bo = new ByteArrayOutputStream();
    //OutputStream op = new ObjectOutputStream();
    ObjectOutputStream oo = new ObjectOutputStream(bo);
    oo.writeObject(this);

    // 從流里讀出來
    InputStream bi = new ByteArrayInputStream(((ByteArrayOutputStream) bo).toByteArray());
    ObjectInputStream oi = new ObjectInputStream(bi);
    return (oi.readObject());
}

然后在拷貝對象時調用重寫的 deepClone() 方法

Book book2 = (Book) b1.deepClone();

結果

age = 34 name = Java開發 price = 30.0

age = 45 name = Android開發 price = 44.0

PS:這樣做的前提是對象以及對象內部所有引用到的對象都是可串行化的,否則,就需要仔細考察那些不可串行化的對象可否設成transient(自行了解)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容

  • 307、setValue:forKey和setObject:forKey的區別是什么? 答:1, setObjec...
    AlanGe閱讀 1,569評論 0 1
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,197評論 30 471
  • 是誰在我腦子里種下這些觀念:金錢如糞土、為富不仁、金錢是萬惡之源……從古到今,很多人參與了,很多還是圣賢。 我不想...
    聽見震撼閱讀 756評論 0 0
  • 愿得一人心 白首不相離 一直在路上,難得有這樣,一個人,悠閑醒來的清晨。思緒,在心靈深處隨意涂鴉,感覺好極了,特別...
    孟婷閱讀 276評論 0 0
  • 2015年10月,你說要請我喝咖啡,我說好啊,其實我一點也不愛喝咖啡。后來我問你為什么會是我呢?大半夜的,你發了一...
    陳清誠閱讀 325評論 0 0