標籤:
在學習IO中的ObjectOutputStream和ObjectInputStream時,會涉及到序列化和還原序列化的應用,那麼它們是什嗎?
一、概念
序列化:把對象轉換為位元組序列的過程,叫做對象的序列化。
還原序列化:把位元組序列恢複為對象的過程,叫做對象的還原序列化。
二、作用
主要有兩種用途:
1.把對象的位元組序列永久儲存在硬碟中,也就是把記憶體中的資料(對象)持久化處理。
2.可以在網路上傳輸對象的字元序列,對象不再局限於本地使用。
無論那種用途,實際上都是為了儲存在記憶體中的各種對象的狀態(也就是執行個體變數,不是方法),並且可以把儲存的對象狀態再讀出來。這是java提供的一種儲存對象狀態的機制。
三、應用
在開頭有提到,在java.io包中有兩個序列化對象的類,分別為:ObjectOutputStream將對象寫入位元組流,ObjectInputStream將位元組流重構為對象。
需要注意的是,被序列化的對象必須要實現Serializable或者Externalizable介面。
例子1:(為了方便閱讀,異常都做拋處理):
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileOutputStream; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 import java.io.Serializable; 7 8 public class Test { 9 public static void main(String[] args) throws Exception{10 Person p = new Person("zhangsan",20);11 serializePerson(p);12 Person p1 = deserializePerson();13 System.out.println(p1); //結果列印zhangsan:20。14 }15 16 // 序列化17 private static void serializePerson(Object obj) throws Exception {18 ObjectOutputStream out= new ObjectOutputStream(new FileOutputStream(new File("c:\\obj.txt")));19 out.writeObject(obj);20 System.out.println("序列化成功");21 out.close();22 }23 24 // 還原序列化25 private static Person deserializePerson() throws Exception {26 ObjectInputStream in = new ObjectInputStream(new FileInputStream("c:\\obj.txt"));27 Person p1 = (Person)in.readObject();28 System.out.println("還原序列化成功");29 in.close();30 return p1;31 }32 33 }34 35 36 class Person implements Serializable {37 // 注意,如果不指定serialVersionUID,序列化時會按預設進行,也會產生serialVersionUID。38 // 但是如果後來有修改類中代碼,序列化產生的serialVersionUID也會改變,這時還原序列化就會失敗,發生異常。39 private static final long serialVersionUID = 1L;40 private String name;41 private int age;42 Person() {43 System.out.println("空參數建構函式");44 }45 public Person(String name, int age) {46 System.out.println("有參數建構函式");47 this.name = name;48 this.age = age;49 }50 51 public String toString() {52 return name+":"+age;53 }54 }
以上代碼運行結果為:
有參數建構函式
序列化成功
還原序列化成功
zhangsan:20
從結果可以看出,還原序列化時,並沒用通過Person類的建構函式,而是根據序列化的資料建立Person對象的。
要注意的是,預設serialVersionUID的取值是Java運行時,根據類的內部細節自動產生的。如果對類的原始碼作了修改,再重新編譯,新產生的類檔案的serialVersionUID的取值有可能也會發生變化。類的serialVersionUID的預設值完全依賴於Java編譯器的實現,對於同一個類,用不同的Java編譯器編譯,有可能會導致不同的 serialVersionUID,也有可能相同。為了提高serialVersionUID的獨立性和確定性,強烈建議在一個可序列化類別中顯示的定義serialVersionUID,為它賦予明確的值。
顯式定義serialVersionUID可以實現兩種目的:
1.若想不同版本的類(類有做過修改)序列化後,都能成功還原序列化(相容),就需要確保類的不同版本的類具有相同的serialVersionUID;
2.若不想不同版本的類序列化後還能成功還原序列化,就讓不同版本的類具有不同的serialVersionUID。
例子2:
先序列化:
1 public class TestSerialze { 2 public static void main(String[] args) throws Exception{ 3 Person p = new Person("zhangsan",20); 4 serializePerson(p); 5 } 6 7 // 序列化 8 private static void serializePerson(Object obj) throws Exception { 9 ObjectOutputStream out= new ObjectOutputStream(new FileOutputStream(new File("c:\\obj.txt")));10 out.writeObject(obj);11 System.out.println("序列化成功");12 out.close();13 }14 }15 16 17 class Person implements Serializable {18 // 注意,如果不指定serialVersionUID,序列化時會按預設進行,也會產生serialVersionUID。19 // 但是如果修改類中內容後,序列化產生新的serialVersionUID,跟原來不一樣,這時還原序列化就會失敗,發生異常。20 private static final long serialVersionUID = 1L;21 private String name;22 private int age;23 // 靜態成員屬於類,不能被序列化。24 private static int count;25 // 瞬態也不能被序列化。26 transient private int key;27 28 Person() {29 System.out.println("空參數建構函式");30 }31 public Person(String name, int age) {32 System.out.println("有參數建構函式");33 this.name = name;34 this.age = age;35 count++;36 key++;37 }38 39 public String toString() {40 return name+":"+age+"..."+count+"..."+key;41 }42 }
後還原序列化:
import java.io.FileInputStream;import java.io.ObjectInputStream;public class TestDeserialze { public static void main(String[] args) throws Exception{ Object obj = deserializeObject(); System.out.println(obj); } private static Object deserializeObject() throws Exception { ObjectInputStream in = new ObjectInputStream(new FileInputStream("c:\\obj.txt")); Object obj = in.readObject(); System.out.println("還原序列化成功"); in.close(); return obj; }}
還原序列化得到的結果是:
還原序列化成功
zhangsan:20...0...0
以上可以看出被static和transient修飾的成員變數無法被序列化。
Java基礎:序列化(Serializable)與還原序列化