java 序列化
java 提供了一種對象序列化的機制,該機制中,一個對象可以被表示為一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。
將序列化對象寫入文件之后,可以從文件中讀取出來,并且對它進行反序列化,也就是說,對象的類型信息、對象的數據,還有對象中的數據類型可以用來在內存中新建對象。
整個過程都是 java 虛擬機(jvm)獨立的,也就是說,在一個平臺上序列化的對象可以在另一個完全不同的平臺上反序列化該對象。
類 objectinputstream 和 objectoutputstream 是高層次的數據流,它們包含反序列化和序列化對象的方法。
objectoutputstream 類包含很多寫方法來寫各種數據類型,但是一個特別的方法例外:
public final void writeobject(object x) throws ioexceptionpublic 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接口。
1. 序列化對象
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(); } } }
2. 反序列化對象
下面的 deserializedemo 程序范例了反序列化,/tmp/employee.ser 存儲了 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
這里要注意以下要點:
readobject() 方法中的 try/catch 代碼塊嘗試捕獲 classnotfoundexception 異常。對于 jvm 可以反序列化對象,它必須是能夠找到字節碼的類。如果jvm在反序列化對象的過程中找不到該類,則拋出一個 classnotfoundexception 異常。
注意,readobject() 方法的返回值被轉化成 employee 引用。
當對象被序列化時,屬性 ssn 的值為 111222333,但是因為該屬性是短暫的,該值沒有被發送到輸出流。所以反序列化后 employee 對象的 ssn 屬性為 0。