Java Serialization/序列化/反序列化
Java提供了一個機製,稱為一個對象可以被表示為字節序列,包括該對象的數據以及關於該對象的類型,並存儲在對象數據的類型的信息的對象序列。
後一個序列化的對象已經被寫入到一個文件中,也可以從文件中讀取和反序列化也就是,表示對象和它的數據可以用於重新創建在存儲器中的對象的類型信息和字節。
最令人印象深刻的是,整個過程是獨立的JVM,這意味著一個對象可以被序列化在一個平台上,並反序列化一個完全不同的平台上。
ObjectInputStream 和 ObjectOutputStream 是包含了方法,序列化和反序列化對象的高層次的數據流。
ObjectOutputStream類包含許多write方法寫入各種數據類型,但在特定的一個方法脫穎而出:
public final void writeObject(Object x) throws IOException
上述方法序列化一個對象,並將其發送到輸出流。同樣,ObjectInputStream的類包含用於反序列化對象的以下方法:
public final Object readObject() throws IOException, ClassNotFoundException
此方法檢索的下一個對象輸出流和反序列化。返回值是Object,所以需要將它轉換成其相應的數據類型。
為了演示序列化的運作方式在Java中,將使用在本教學中在前麵討論的Employee類。假設我們有以下的Employee類,它實現了Serializable接口:
public class Employee implements java.io.Serializable { public String name; public String address; public transient int SSN; public int number; public void mailCheck() { System.out.println("Mailing a check to " + name + " " + address); } }
請注意,一類被序列化成功,兩個條件必須滿足:
-
這個類必須實現java.io.Serializable接口。
-
所有在類中的字段必須是可序列化的。如果一個字段不是可序列化的,必須注明短暫的。
如果想知道,一個Java標準類是可序列化與否,請檢查類的文檔。測試很簡單:如果一個類實現了java.io.Serializable,那麼它是可序列化的,否則,它不是。
序列化一個對象:
ObjectOutputStream類用於序列化一個對象。下麵SerializeDemo程序實例化一個Employee對象,並將其序列化到一個文件中。
當程序執行完畢,一個名為employee.ser被創建。程序不會產生任何輸出,但研究代碼,並嘗試確定哪些程序正在做什麼。
注:當序列化一個對象到一個文件中,在Java標準慣例給定的文件擴展名為 .ser 。
import java.io.*; public class SerializeDemo { public static void main(String [] args) { Employee e = new Employee(); e.name = "Reyan Ali"; e.address = "Phokka Kuan, Ambehta Peer"; e.SSN = 11122333; e.number = 101; try { FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(e); out.close(); fileOut.close(); System.out.printf("Serialized data is saved in /tmp/employee.ser"); }catch(IOException i) { i.printStackTrace(); } } }
反序列化對象:
下麵DeserializeDemo程序反序列化的SerializeDemo程序創建的Employee對象。研究程序,並嘗試確定其輸出:
import java.io.*; public class DeserializeDemo { public static void main(String [] args) { Employee e = null; try { FileInputStream fileIn = new FileInputStream("/tmp/employee.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); e = (Employee) in.readObject(); in.close(); fileIn.close(); }catch(IOException i) { i.printStackTrace(); return; }catch(ClassNotFoundException c) { System.out.println("Employee class not found"); c.printStackTrace(); return; } System.out.println("Deserialized Employee..."); System.out.println("Name: " + e.name); System.out.println("Address: " + e.address); System.out.println("SSN: " + e.SSN); System.out.println("Number: " + e.number); } }
這將產生以下結果:
Deserialized Employee... Name: Reyan Ali Address:Phokka Kuan, Ambehta Peer SSN: 0 Number:101
這裡有以下重要點要注意:
-
try/catch塊試圖捕獲一個ClassNotFoundException,這是由readObject()方法聲明。對於一個JVM能夠反序列化對象時,它必須能夠找到的字節碼的類。如果JVM不能對象的反序列化過程中發現的一類,它拋出一個ClassNotFoundException。
-
請注意,調用readObject()返回值被強製轉換為Employee 參考。
-
SSN字段的值是11122333當對象被序列化,但因為該字段是短暫的,這個值是不會被發送到輸出流。反序列化的Employee對象的SSN字段為0。