一、前言
複習Java基礎知識點的序列化與反序列化過程,整理了如下學習筆記。
二、為什麼需要序列化與反序列化
程式執行時,只要需要,物件可以一直存在,並且我們可以隨時訪問物件的一些狀態資訊,如果程式終止,那麼物件是肯定不會存在的,但是有時候,我們需要再程式終止時儲存物件的狀態資訊,之後程式再次執行時可以重新恢復到之前的狀態,如,玩家玩遊戲退出時,需要儲存玩家的狀態資訊(如等級、裝備等等),之後玩家再此登入時,必須要恢復這些狀態資訊。我們可以通過資料庫手段來達到這個儲存狀態的目的,在Java中,我們有更簡便的方法進行處理,那就是序列化與反序列化。序列化是一種物件持久化的手段,反序列化與序列化相反,其是通過序列化後的資訊重新組裝成物件。序列化與反序列化普遍應用在網路傳輸、RMI等場景中。
三、序列化概述
3.1 序列化類結構圖
下面展示了與序列化相關的類的結構圖
說明:虛線框的表示介面型別,實線框表示具體的類。
3.2 序列化關鍵字說明
與序列化相關的關鍵字如下
說明:
1. 關鍵字transient,用來修飾欄位,表示此欄位在預設序列化過程中不會被處理,但是可以採用另外的手段進行處理。
2. 關鍵字serialVersionUID,表示序列化版本號,當兩個類的序列化ID一致時允許反序列化,預設可以採用編譯器提供的值1L。
3.3 序列化方法說明
與序列化相關的方法如下
說明:writeObject與readObject方法分別在ObjectOutput介面與ObjectInput介面中宣告,在ObjectOutputStream與ObjectInputStream中實現。
四、Serializable
4.1 Serializable定義
Serializable定義如下
public interface Serializable { }
說明:Serializable為一個介面,並且沒有任何欄位和方法,僅僅作為一個標識。
4.2 使用說明
當序列化物件時,只需要將物件標記為可序列化,即實現介面Serializable即可。下面的Person類實現了Serializable介面。
package com.hust.grid.leesf.serializable; import java.io.Serializable; public class Person implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } @Override public String toString() { return "name = " + name + ", gender = " + gender + ", age = " + age + ", friend info is [" + friend + "]"; } }
Person類的friend欄位設定為transient,表明不會被序列化,定義完Person類之後,我們即可以對Person類進行序列化與反序列化操作了,具體程式碼如下
package com.hust.grid.leesf.serializable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SerializableDemo { public static void main(String[] args) throws Exception { Person leesf = new Person(); Person dyd = new Person(); leesf.setAge(24); leesf.setGender("man"); leesf.setName("leesf"); dyd.setAge(24); dyd.setGender("woman"); dyd.setName("dyd"); leesf.setFriend(dyd); dyd.setFriend(null); File file = new File("test"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(leesf); oos.flush(); oos.close(); System.out.println(leesf); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); leesf = (Person) ois.readObject(); ois.close(); System.out.println(leesf); } }
執行結果如下
name = leesf, gender = man, age = 24, friend info is [name = dyd, gender = woman, age = 24, friend info is [null]] name = leesf, gender = man, age = 24, friend info is [null]
說明:由於friend欄位標記為transient,則預設序列化操作時不會進行序列化,反序列化後其值為null。
4.3 問題說明
1. Person類不實現Serializable介面
若Person類不實現Serializable介面,進行序列化時,會發生什麼,會出現如下異常。
Exception in thread "main" java.io.NotSerializableException:****
表示Person沒有實現Serializable介面,具體原因如下
在呼叫writeObject方法後,會經過一系列的呼叫,具體的呼叫棧如下
說明:擷取了writeObject0函式中的一段程式碼,可以看到會檢查該物件是否是Serializable型別,不是,則會丟擲異常。
2. 處理transient物件
當欄位被transient修飾時,採用預設的序列化機制將不會對其進行處理,但是,如果要序列化transient欄位時,如何做呢,可以在要進行序列化的類中新增writeObject和readObject方法,其方法簽名如下
private void writeObject(ObjectOutputStream stream) throws IOException private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
說明:注意,writeObject與readObject是採用private修飾符修飾的,說明,此方法只能在該類的其他方法中被呼叫,其他類中不能呼叫此方法,那麼當呼叫ObjectOutputStream的writeObject方法時,如何呼叫到此方法來執行使用者自定義處理邏輯的呢,答案是反射。利用反射可以在別的類中呼叫到此類中私有的方法,反射很強大。
利用這個方法,我們修改Person類如下
package com.hust.grid.leesf.serializable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class Person implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } @Override public String toString() { return "name = " + name + ", gender = " + gender + ", age = " + age + ", friend info is [" + friend + "]"; } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeObject(friend); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); friend = (Person) stream.readObject(); } }
測試類的程式碼不做修改,執行結果如下
name = leesf, gender = man, age = 24, friend info is [name = dyd, gender = woman, age = 24, friend info is [null]] name = leesf, gender = man, age = 24, friend info is [name = dyd, gender = woman, age = 24, friend info is [null]]
說明:在實現自定義的邏輯時,在writeObject方法中可以呼叫defaultWriteObject()方法實現預設序列化(序列化非transient欄位),可以單獨處理transient關鍵字;在readObject方法中可以呼叫defaultReadObject()方法實現預設反序列化,可以單獨處理transient關鍵字(需要賦值)。值得注意的是,writeObject方法中defaultWriteObject和處理transient關鍵字的邏輯必須與readObject中defaultReadObject和處理transient關鍵字的邏輯順序一致,否則會丟擲異常。
在呼叫writeObject方法後,會經過一系列的呼叫,具體的呼叫棧如下
說明:經過反射,最終會呼叫到在Person類中定義的writeObject方法。readObject方法的呼叫可以以此類比,不再累贅。
五、Externalizable
除了使用Serializable介面進行序列化以外,還可以使用Externalizable介面來進行序列化。
5.1 Externalizable定義
Externalizable的定義如下
public interface Externalizable extends java.io.Serializable { void writeExternal(ObjectOutput out) throws IOException; void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; }
說明:Externalizable實現了Serializable介面,並且新增了兩個方法writeExternal與readExternal,需要序列化的類需要實現Externalizable介面,並且重寫介面中定義的兩個方法。
5.2 使用說明
首先將序列化的類實現Externalizable介面並且重寫writeExternal與readExternal方法,並在這兩個方法中實現處理邏輯。我們定義Person類如下
package com.hust.grid.leesf.serializable; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; public class Person implements Externalizable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } @Override public String toString() { return "name = " + name + ", gender = " + gender + ", age = " + age + ", friend info is [" + friend + "]"; } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(name); out.writeUTF(gender); out.writeInt(age); out.writeObject(friend); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = in.readUTF(); gender = in.readUTF(); age = in.readInt(); friend = (Person) in.readObject(); } }
說明:Person類實現了Externalizable介面,重寫了writeExternal與readExternal方法,並且實現了使用者自定義序列化與反序列化邏輯。測試類程式碼不變,執行結果如下:
name = leesf, gender = man, age = 24, friend info is [name = dyd, gender = woman, age = 24, friend info is [null]] name = leesf, gender = man, age = 24, friend info is [name = dyd, gender = woman, age = 24, friend info is [null]]
說明:從結果可知,成功進行了序列化與反序列化過程。值得注意的是,我們必須要給Person類提供一個無參構造器,才能正確完成序列化與反序列化過程。否則會丟擲如下異常
修改Person類如下
package com.hust.grid.leesf.serializable; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; public class Person implements Externalizable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } @Override public String toString() { return "name = " + name + ", gender = " + gender + ", age = " + age + ", friend info is [" + friend + "]"; } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(name); out.writeUTF(gender); out.writeInt(age); out.writeObject(friend); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = in.readUTF(); gender = in.readUTF(); age = in.readInt(); friend = (Person) in.readObject(); } }
說明:提供一個引數的建構函式,沒有無參建構函式,修改測試類程式碼如下
package com.hust.grid.leesf.serializable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SerializableDemo { public static void main(String[] args) throws Exception { Person leesf = new Person("leesf"); Person dyd = new Person("dyd"); leesf.setAge(24); leesf.setGender("man"); leesf.setName("leesf"); dyd.setAge(24); dyd.setGender("woman"); dyd.setName("dyd"); leesf.setFriend(dyd); dyd.setFriend(null); File file = new File("test"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(leesf); oos.flush(); oos.close(); System.out.println(leesf); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); leesf = (Person) ois.readObject(); ois.close(); System.out.println(leesf); } }
執行結果如下
name = leesf, gender = man, age = 24, friend info is [name = dyd, gender = woman, age = 24, friend info is [null]] Exception in thread "main" java.io.InvalidClassException: com.hust.grid.leesf.serializable.Person; no valid constructor at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150) at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:768) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1775) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) at com.hust.grid.leesf.serializable.SerializableDemo.main(SerializableDemo.java:32)
說明:在反序列化的過程丟擲了異常,可以看出是Person類沒有合法的構造器,合法的構造器就是指無參構造器。當提供了無參構造器之後,就可以正確執行。
5.3 問題說明
1. Externalizable,writeObject與readObject方法
如果Person類實現了Externalizable介面,並且在Person類中新增了writeObject與readObject方法,那麼在進行序列化與反序列化時,是以哪種方法為準呢,修改Person類如下
package com.hust.grid.leesf.serializable; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; public class Person implements Externalizable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } @Override public String toString() { return "name = " + name + ", gender = " + gender + ", age = " + age + ", friend info is [" + friend + "]"; } @Override public void writeExternal(ObjectOutput out) throws IOException { System.out.println("use writeExternal method"); out.writeUTF(name); out.writeUTF(gender); out.writeInt(age); out.writeObject(friend); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("use readExternal method"); name = in.readUTF(); gender = in.readUTF(); age = in.readInt(); friend = (Person) in.readObject(); } private void writeObject(ObjectOutputStream stream) throws IOException { System.out.println("use writeObject method"); stream.defaultWriteObject(); stream.writeObject(friend); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { System.out.println("use readObject method"); stream.defaultReadObject(); friend = (Person) stream.readObject(); } }
說明:在方法中新增了列印語句,這樣就可以輕易判別採用的何種方式。測試類程式碼如下
package com.hust.grid.leesf.serializable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SerializableDemo { public static void main(String[] args) throws Exception { Person leesf = new Person(); Person dyd = new Person(); leesf.setAge(24); leesf.setGender("man"); leesf.setName("leesf"); dyd.setAge(24); dyd.setGender("woman"); dyd.setName("dyd"); leesf.setFriend(dyd); dyd.setFriend(null); File file = new File("test"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(leesf); oos.flush(); oos.close(); System.out.println(leesf); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); leesf = (Person) ois.readObject(); ois.close(); System.out.println(leesf); } }
執行結果
use writeExternal method use writeExternal method name = leesf, gender = man, age = 24, friend info is [name = dyd, gender = woman, age = 24, friend info is [null]] use readExternal method use readExternal method name = leesf, gender = man, age = 24, friend info is [name = dyd, gender = woman, age = 24, friend info is [null]]
說明:從結果可以看出,是以Externalizable介面中定義的兩個方法進行序列化與反序列化的,這時,讀者可能又會有另外一個疑問,那就是為什麼會列印兩次呢?答案是因為該方法被呼叫了兩次,因為Person類有一個Person域,會導致呼叫兩次。
2. 處理transient欄位
可以在writeExternal與readExternal方法中實現自定義邏輯,對transient欄位進行序列化與反序列化。
六、序列化問題
6.1 採用預設序列化機制,類的靜態欄位會被序列化嗎?
採用預設序列化機制進行序列化時,類的靜態欄位會被序列化嗎,此時類的靜態欄位不會被序列化,當然,我們可以採用自定義序列化邏輯對靜態變數進行序列化。
6.2 父類序列化問題
採用預設序列化機制序列化子類時,其父類的欄位會被序列化嗎?可以分為如下情形
1. 父類沒有實現Serializable介面,沒有提供預設建構函式
這時,反序列化會出錯,提示沒有提供正確的建構函式。修改Person類,程式碼如下
package com.hust.grid.leesf.serializable; import java.io.Serializable; class Human { private int number; public Human(int number) { this.number = number; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public String toString() { return "number = " + number; } } public class Person extends Human implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person(int number, String name) { super(number); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } @Override public String toString() { return super.toString() + ", name = " + name + ", gender = " + gender + ", age = " + age + ", friend info is [" + friend + "]"; } }
測試類的的程式碼如下
package com.hust.grid.leesf.serializable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SerializableDemo { public static void main(String[] args) throws Exception { Person leesf = new Person(1, "leesf"); Person dyd = new Person(2, "dyd"); leesf.setAge(24); leesf.setGender("man"); leesf.setName("leesf"); dyd.setAge(24); dyd.setGender("woman"); dyd.setName("dyd"); leesf.setFriend(dyd); dyd.setFriend(null); File file = new File("test"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(leesf); oos.flush(); oos.close(); System.out.println(leesf); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); leesf = (Person) ois.readObject(); ois.close(); System.out.println(leesf); } }
執行結果
number = 1, name = leesf, gender = man, age = 24, friend info is [number = 2, name = dyd, gender = woman, age = 24, friend info is [null]] Exception in thread "main" java.io.InvalidClassException: com.hust.grid.leesf.serializable.Person; no valid constructor at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150) at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:768) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1775) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) at com.hust.grid.leesf.serializable.SerializableDemo.main(SerializableDemo.java:32)
說明:可以看出是沒有提供合法的建構函式。
2. 父類沒有實現Serializable介面,提供預設建構函式
第一步中出現了錯誤,此時,我們修改Person類,程式碼如下
package com.hust.grid.leesf.serializable; import java.io.Serializable; class Human { private int number; public Human() { } public Human(int number) { this.number = number; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public String toString() { return "number = " + number; } } public class Person extends Human implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person() { super(); } public Person(int number, String name) { super(number); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } @Override public String toString() { return super.toString() + ", name = " + name + ", gender = " + gender + ", age = " + age + ", friend info is [" + friend + "]"; } }
說明:給Human類提供了無參建構函式。測試類程式碼不變,執行結果如下
number = 1, name = leesf, gender = man, age = 24, friend info is [number = 2, name = dyd, gender = woman, age = 24, friend info is [null]] number = 0, name = leesf, gender = man, age = 24, friend info is [null]
說明:此時,我們可以看到,可以進行反序列化了,但是父類的number欄位被賦值為int的預設值0,Person類的transient欄位沒有被序列化。
3. 父類實現Serializable介面
當父類實現Serializable介面時,修改Person類程式碼如下
package com.hust.grid.leesf.serializable; import java.io.Serializable; class Human implements Serializable { /** * */ private static final long serialVersionUID = 1L; private int number; public Human() { } public Human(int number) { this.number = number; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public String toString() { return "number = " + number; } } public class Person extends Human implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person() { super(); } public Person(int number, String name) { super(number); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } @Override public String toString() { return super.toString() + ", name = " + name + ", gender = " + gender + ", age = " + age + ", friend info is [" + friend + "]"; } }
測試類的程式碼不變,執行結果如下
number = 1, name = leesf, gender = man, age = 24, friend info is [number = 2, name = dyd, gender = woman, age = 24, friend info is [null]] number = 1, name = leesf, gender = man, age = 24, friend info is [null]
說明:從結果可知,已經可以進行正確的序列化與反序列化了,子類的transient欄位沒有被序列化。
6.3 共享物件序列化問題
當序列化的兩個物件都包含另外一個物件的引用時,在反序列化時,另外一個物件只會出現一次嗎?修改Person類程式碼如下
package com.hust.grid.leesf.serializable; import java.io.Serializable; public class Person implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String name; private String gender; private int age; private transient Person friend; public Person() { } public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person getFriend() { return friend; } public void setFriend(Person friend) { this.friend = friend; } }
測試類程式碼如下
package com.hust.grid.leesf.serializable; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; public class SerializableDemo { @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { Person leesf = new Person("leesf"); Person dyd = new Person("dyd"); Person lr = new Person("lr"); leesf.setAge(24); leesf.setGender("man"); dyd.setAge(24); dyd.setGender("woman"); lr.setAge(25); lr.setGender("man"); leesf.setFriend(dyd); lr.setFriend(dyd); dyd.setFriend(null); List<Person> persons = new ArrayList<Person>(); persons.add(leesf); persons.add(dyd); persons.add(lr); ByteArrayOutputStream bos1 = new ByteArrayOutputStream(); ByteArrayOutputStream bos2 = new ByteArrayOutputStream(); ObjectOutputStream oos1 = new ObjectOutputStream(bos1); oos1.writeObject(persons); oos1.writeObject(persons); ObjectOutputStream oos2 = new ObjectOutputStream(bos2); oos2.writeObject(persons); ByteArrayInputStream bis1 = new ByteArrayInputStream(bos1.toByteArray()); ByteArrayInputStream bis2 = new ByteArrayInputStream(bos2.toByteArray()); ObjectInputStream ois1 = new ObjectInputStream(bis1); ObjectInputStream ois2 = new ObjectInputStream(bis2); List<Person> persons1 = (List<Person>) ois1.readObject(); List<Person> persons2 = (List<Person>) ois1.readObject(); List<Person> persons3 = (List<Person>) ois2.readObject(); System.out.println(persons1); System.out.println(persons2); System.out.println(persons3); } }
執行結果如下
[com.hust.grid.leesf.serializable.Person@7f31245a, com.hust.grid.leesf.serializable.Person@6d6f6e28, com.hust.grid.leesf.serializable.Person@135fbaa4]
[com.hust.grid.leesf.serializable.Person@7f31245a, com.hust.grid.leesf.serializable.Person@6d6f6e28, com.hust.grid.leesf.serializable.Person@135fbaa4]
[com.hust.grid.leesf.serializable.Person@45ee12a7, com.hust.grid.leesf.serializable.Person@330bedb4, com.hust.grid.leesf.serializable.Person@2503dbd3]
說明:從結果可知,oos1執行的writeObject是向同一個記憶體空間寫了兩次,從結果可看出,兩次寫入的物件的地址空間都是一樣的,即進行了淺拷貝。而oos2執行的writeObject是向另外一個記憶體空間寫了一次,從結果可看出,因為物件的地址不同於之前的物件地址,即採用了深拷貝。
七、總結
寫到這裡,關於Java中的序列化與反序列化機制就已經分析完了,經過此次分析,對序列化機制的認識更加深刻。學習一個知識點,就要認認真真,踏踏實實的弄懂一個知識點,寫部落格就是一個特別好的方式。謝謝各位園友的觀看~
參考連結
http://blog.csdn.net/jiangwei0910410003/article/details/18989711/
http://www.hollischuang.com/archives/1140