基於序列化存取實現java對象深度複製的方法詳解

來源:互聯網
上載者:User

我們知道,在java中,將一個非原型類型類型的對象引用,賦值給另一個對象的引用之後,這兩個引用就指向了同一個對象,如: 複製代碼 代碼如下:public class DeepCloneTest {

private class CloneTest {
private Long myLong = new Long(1);
}

public static void main(String args[]) {
new DeepCloneTest().Test();
}

public void Test() {
CloneTest ct1 = new CloneTest();
CloneTest ct2 = ct1;

// to see if ct1 and ct2 are one same reference.
System.out.println("ct1: " + ct1);
System.out.println("ct2: " + ct2);

// if ct1 and ct2 point to one same object, then ct1.myLong == ct2.myLong.
System.out.println("ct1.myLong: " + ct1.myLong);
System.out.println("ct2.myLong: " + ct2.myLong);

// we change ct2's myLong
ct2.myLong = 2L;

// to see whether ct1's myLong was changed.
System.out.println("ct1.myLong: " + ct1.myLong);
System.out.println("ct2.myLong: " + ct2.myLong);
}
}

out put:
ct1: DeepCloneTest$CloneTest@c17164
ct2: DeepCloneTest$CloneTest@c17164
ct1.myLong: 1
ct2.myLong: 1
ct1.myLong: 2
ct2.myLong: 2
這個很easy,估計學java的都知道(不知道的是學java的嗎?)。
在記憶體中,對象的引用存放在棧中,對象的資料,存放在堆中,棧中的引用指向了堆中的對象。這裡就是兩個棧中的引用,指向了堆中的同一個對象,所以,當改變了 ct2 的 myLong,可以看到,ct1 的 myLong 值也隨之改變,如果用圖來表示,就很容易理解了:

左邊的是棧區,該區中有兩個引用,值相同,它們指向了右邊堆區的同一個對象。
大多時候,我們會用 java 語言的這一特性做我們想做的事情,比如,將對象的引用作為入參傳入一個方法中,在方法中,對引用所指對象做相應修改。但有時,我們希望構造出一個和已經存在的對象具有完全相同的內容,但引用不同的對象,為此,可以這樣做複製代碼 代碼如下:public class DeepCloneTest{

// must implements Cloneable.
private class CloneTest implements Cloneable{
private Object o = new Object();

public CloneTest clone() {
CloneTest ct = null;
try {
ct = (CloneTest)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return ct;
}
}

public static void main(String args[]) {
new DeepCloneTest().Test();
}

public void Test() {
CloneTest ct1 = new CloneTest();
CloneTest ct2 = ct1.clone();

// to see if ct1 and ct2 are one same reference.
System.out.println("ct1: " + ct1);
System.out.println("ct2: " + ct2);

// whether ct1.o == ct2.o ? yes
System.out.println("ct1.o " + ct1.o);
System.out.println("ct1.o " + ct1.o);
}
}

out put:
ct1: DeepCloneTest$CloneTest@c17164
ct2: DeepCloneTest$CloneTest@1fb8ee3
ct1.o java.lang.Object@61de33
ct1.o java.lang.Object@61de33
從輸出可以看出:ct1 和 ct2 確實是兩個不同的引用,所以我們想當然的認為,ct1.o 和 ct2.o 也是兩個不同的對象了,但從輸出可以看出並非如此!ct1.o 和 ct2.o 是同一個對象!原因在於,雖然用到了複製,但上面只是淺度複製,用圖形來表示:


看到上面的 o 了嗎?其實是兩個對象共用的。這就相當於,你本來有一個羊圈1,裡面有一隻羊,然後你又弄了一個羊圈2,在不將羊從羊圈1裡牽出來的情況下,將羊也圈在了羊圈2中,你以為你有兩條羊了,其實呢?大家都知道。

這就是淺度複製的結果:如果你想讓兩個對象具有獨立的 o,就必須再對 o 做複製操作。可能有些人認為這沒有什麼,做就做唄,但想過沒有,如果不止一個 o, 還有很多很多的類似 o 的東東,你都逐一去做複製嗎?顯然是不太現實的。

一種解決方案是:將對象先序列化儲存到流中,然後再從留中讀出對象,這樣就可以保證讀取出來的資料和之前的對象,裡面的值完全相同,就像是一個完全的拷貝。複製代碼 代碼如下:import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepCloneTest {

// must implements Cloneable.
private class CloneTest implements Serializable{
private static final long serialVersionUID = 1L;
private Object o = new Object();

public CloneTest deepClone() {
CloneTest ct = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois= new ObjectInputStream(bais);
ct = (CloneTest)ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return ct;
}
}

public static void main(String args[]) {
new DeepCloneTest().Test();
}

public void Test() {
CloneTest ct1 = new CloneTest();
CloneTest ct2 = ct1.deepClone();

// to see if ct1 and ct2 are one same reference.
System.out.println("ct1: " + ct1);
System.out.println("ct2: " + ct2);

// whether ct1.o == ct2.o ? no
System.out.println("ct1.o " + ct1.o);
System.out.println("ct1.o " + ct1.o);
}
}

這個時候,記憶體中的資料就是這樣的了:

複製任務完成。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.