java 序列化
java 提供了一種對(duì)象序列化的機(jī)制,該機(jī)制中,一個(gè)對(duì)象可以被表示為一個(gè)字節(jié)序列,該字節(jié)序列包括該對(duì)象的數(shù)據(jù)、有關(guān)對(duì)象的類型的信息和存儲(chǔ)在對(duì)象中數(shù)據(jù)的類型。
將序列化對(duì)象寫(xiě)入文件之后,可以從文件中讀取出來(lái),并且對(duì)它進(jìn)行反序列化,也就是說(shuō),對(duì)象的類型信息、對(duì)象的數(shù)據(jù),還有對(duì)象中的數(shù)據(jù)類型可以用來(lái)在內(nèi)存中新建對(duì)象。
整個(gè)過(guò)程都是 java 虛擬機(jī)(jvm)獨(dú)立的,也就是說(shuō),在一個(gè)平臺(tái)上序列化的對(duì)象可以在另一個(gè)完全不同的平臺(tái)上反序列化該對(duì)象。
類 objectinputstream 和 objectoutputstream 是高層次的數(shù)據(jù)流,它們包含反序列化和序列化對(duì)象的方法。
objectoutputstream 類包含很多寫(xiě)方法來(lái)寫(xiě)各種數(shù)據(jù)類型,但是一個(gè)特別的方法例外:
public final void writeobject(object x) throws ioexceptionpublic final void writeobject(object x) throws ioexception
上面的方法序列化一個(gè)對(duì)象,并將它發(fā)送到輸出流。相似的 objectinputstream 類包含如下反序列化一個(gè)對(duì)象的方法:
public final object readobject() throws ioexception, classnotfoundexception
該方法從流中取出下一個(gè)對(duì)象,并將對(duì)象反序列化。它的返回值為 object,因此,你需要將它轉(zhuǎn)換成合適的數(shù)據(jù)類型。
為了演示序列化在 java 中是怎樣工作的,我將使用之前教程中提到的 employee 類,假設(shè)我們定義了如下的 employee 類,該類實(shí)現(xiàn)了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); } }
請(qǐng)注意,一個(gè)類的對(duì)象要想序列化成功,必須滿足兩個(gè)條件:
該類必須實(shí)現(xiàn) java.io.serializable 接口。
該類的所有屬性必須是可序列化的。如果有一個(gè)屬性不是可序列化的,則該屬性必須注明是短暫的。
如果你想知道一個(gè) java 標(biāo)準(zhǔn)類是否是可序列化的,請(qǐng)查看該類的文檔。檢驗(yàn)一個(gè)類的范例是否能序列化十分簡(jiǎn)單, 只需要查看該類有沒(méi)有實(shí)現(xiàn) java.io.serializable接口。
1. 序列化對(duì)象
objectoutputstream 類用來(lái)序列化一個(gè)對(duì)象,如下的 serializedemo 例子范例化了一個(gè) employee 對(duì)象,并將該對(duì)象序列化到一個(gè)文件中。
該程序執(zhí)行后,就創(chuàng)建了一個(gè)名為 employee.ser 文件。該程序沒(méi)有任何輸出,但是你可以通過(guò)代碼研讀來(lái)理解程序的作用。
注意: 當(dāng)序列化一個(gè)對(duì)象到文件時(shí), 按照 java 的標(biāo)準(zhǔn)約定是給文件一個(gè) .ser 擴(kuò)展名。
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. 反序列化對(duì)象
下面的 deserializedemo 程序范例了反序列化,/tmp/employee.ser 存儲(chǔ)了 employee 對(duì)象。
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); } }
以上程序編譯運(yùn)行結(jié)果如下所示:
deserialized employee... name: reyan ali address:phokka kuan, ambehta peer ssn: 0 number:101
這里要注意以下要點(diǎn):
readobject() 方法中的 try/catch 代碼塊嘗試捕獲 classnotfoundexception 異常。對(duì)于 jvm 可以反序列化對(duì)象,它必須是能夠找到字節(jié)碼的類。如果jvm在反序列化對(duì)象的過(guò)程中找不到該類,則拋出一個(gè) classnotfoundexception 異常。
注意,readobject() 方法的返回值被轉(zhuǎn)化成 employee 引用。
當(dāng)對(duì)象被序列化時(shí),屬性 ssn 的值為 111222333,但是因?yàn)樵搶傩允嵌虝旱?,該值沒(méi)有被發(fā)送到輸出流。所以反序列化后 employee 對(duì)象的 ssn 屬性為 0。