精華區beta java 關於我們 聯絡資訊
在物件導向當中,如何將物件裡的資料簡易方便的保存或傳輸, 而不用繁雜的訂定格式、解析資料等,不是個簡單的問題。 所幸在Java的世界裡有序列化這方便好用的功能。 輕易的將物件序列化後就可透過各種資料流保存或傳輸。 相信大家也對序列化都很熟悉了。 這邊想提的是最近我寫程式用到序列化時,忽略掉的細節。 「多個有互相參照的序列化物件儲存問題」 假設今天有兩個序列化的類別如下: public class A implements Serializable { public B b; } public class B implements Serializable { public A a; } 兩個物件互相參照: A a = new A(); B b = new B(); a.b = b; b.a = a; 想當然爾: System.out.println(a.b == b); System.out.println(a.b.a == a); System.out.println(b.a == a); System.out.println(b.a.b == b); 印出來的是: true true true true 分別寫入兩個檔案: FileOutputStream fos = new FileOutputStream("a.object"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(a); oos.close(); fos = new FileOutputStream("b.object"); oos = new ObjectOutputStream(fos); oos.writeObject(b); oos.close(); 嗯,沒錯誤發生。 可見互相參考甚至是循環參考對物件的序列化是沒問題的。 在別的程式裡,讀出那兩個物件來: FileInputStream fis = new FileInputStream("a.object"); ObjectInputStream ois = new ObjectInputStream(fis); A a = (A)ois.readObject(); fis = new FileInputStream("b.object"); ois = new ObjectInputStream(fis); B b = (B)ois.readObject(); 此時: System.out.println(a.b == b); System.out.println(a.b.a == a); System.out.println(b.a == a); System.out.println(b.a.b == b); 印出來的是: false true false true 哎呀!參照居然變了! 那改成都在同一個資料流呢? 物件輸出資料流用同一個再寫一次: A a = new A(); B b = new B(); a.b = b; b.a = a; FileOutputStream fos = new FileOutputStream("objects"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(a); oos.writeObject(b); oos.close(); 在別的程式裡,讀出那兩個物件來: FileInputStream fis = new FileInputStream("objects"); ObjectInputStream ois = new ObjectInputStream(fis); A a = (A)ois.readObject(); B b = (B)ois.readObject(); ois.close(); 此時: System.out.println(a.b == b); System.out.println(a.b.a == a); System.out.println(b.a == a); System.out.println(b.a.b == b); 印出來的是: true true true true 終於是原先要的結果了...XD 我想,在我們寫程式寫的忙得時候, 往往會忽略一些小細節。 所以發這篇提醒自己也提醒大家, 希望會有所幫助... ^^ -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.113.65.151 > -------------------------------------------------------------------------- < 作者: NTUtzboy (台大資男喲) 看板: java 標題: Re: [心得] 序列化的小細節 時間: Thu Oct 26 01:37:30 2006 問題出在這:(節錄自J2SE1.4 API)  The default serialization mechanism for an object writes the class of the object, the class signature, and the values of all non-transient and non-static fields. References to other objects (except in transient or static fields) cause those objects to be written also. Multiple references to a single object are encoded using a reference sharing mechanism so that graphs of objects can be restored to the same shape as when the original was written. 所以"a.object"儲存了兩個物件, "b.object"也同樣儲存了兩個物件 (不信的話可以直接把a.object檔打開看, 一定看的懂的...) 因此讀取的結果是, A有兩個instances, B也有兩個 其中某個A.b是指向一個B instance; 另一個A的refernce b則是指向另一個B instance 自己畫畫圖就很清楚了... 不過也很感謝p大找出這個問題呢:) ※ 引述《PsMonkey (痞子軍團團長)》之銘言: : 請原諒我幫忙加個註解... : (坦白說,我翻來翻去,看好久才知道確定差異在哪 XDXD) : ※ 引述《pao0111 (Pao)》之銘言: : : 分別寫入兩個檔案: : //這是會導致 reference 失敗的寫法 : //差異點在於,這邊存在兩個不同的檔案當中 : : FileOutputStream fos = new FileOutputStream("a.object"); : : ObjectOutputStream oos = new ObjectOutputStream(fos); : : oos.writeObject(a); : : oos.close(); : : fos = new FileOutputStream("b.object"); : : oos = new ObjectOutputStream(fos); : : oos.writeObject(b); : : oos.close(); : : 嗯,沒錯誤發生。 : : 可見互相參考甚至是循環參考對物件的序列化是沒問題的。 : : 在別的程式裡,讀出那兩個物件來: : : FileInputStream fis = new FileInputStream("a.object"); : : ObjectInputStream ois = new ObjectInputStream(fis); : : A a = (A)ois.readObject(); : : fis = new FileInputStream("b.object"); : : ois = new ObjectInputStream(fis); : : B b = (B)ois.readObject(); : : 此時: : : System.out.println(a.b == b); : : System.out.println(a.b.a == a); : : System.out.println(b.a == a); : : System.out.println(b.a.b == b); : : 印出來的是: : : false : : true : : false : : true : : 哎呀!參照居然變了! : 我比較想知道,這時候的 a.b 會指到哪裡去 @__@??? : 為甚麼 a.b.a 又會指回來自己 @__@??? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.139.216.85 ※ 編輯: NTUtzboy 來自: 220.139.216.85 (10/26 01:38)