更新時間:2019-09-29 09:26:15 來源:動力節點 瀏覽2828次
我們最常使用的創建對象的方式,就是使用new運算符來創建對象,并使用之。比如,如果你有一個Student類,在其構造函數中接受一個人的name,gender和height作為參數,你可以創建一個Student對象,如下所示:
Studentzhangsan=newPerson("張三","男",6.7);
如果你想將對象zhangsan保存到文件中,然后在不使用new運算符的情況下將其恢復到內存中,那該怎么做呢?本節就來討論這個主題內容。
首先要明白,將內存中的對象轉換為字節序列并將字節序列存儲在諸如文件的存儲介質中的過程稱為對象序列化。你可以將字節序列存儲到永久存儲器中,例如文件或數據庫;還可以通過網絡傳輸字節序列。從存儲器中讀取序列化過程產生的字節序列并將對象恢復到內存中的過程稱為對象反序列化。對象的序列化也稱為對對象進行壓縮或編組。對象的反序列化也稱為對對象進行復原或解組。可以將序列化視為將對象從內存寫入存儲介質,將反序列化視為從存儲介質將對象讀入內存。
完成這兩類工作的是ObjectOutputStream類和ObjectInputStream類
ObjectOutputStream類的對象用于序列化對象。ObjectInputStream類的對象用于反序列化對象。你還可以使用這些類的對象來序列化原始數據類型的值,例如int,double,boolean等。
ObjectOutputStream和ObjectInputStream類分別是輸出和輸入流的具體裝飾器類(IO族系類中裝飾器用的非常之多)。但是,它們不是從它們的抽象裝飾器類繼承而來的。它們是從各自的抽象組件類繼承而來的。ObjectOutputStream繼承自OutputStream,ObjectInputStream繼承自InputStream。貌似這與裝飾模式不一致的。其實,這仍然適合裝飾器模式(這里就不展開了)。
關于對象序列化,你的需要序列的對象的類,其必須實現Serializable或Externalizable接口,只有這樣了,才能進行序列化或反序列化。Serializable接口是一個標記接口(沒有任何成員)。如果希望序列化Student類的對象,則需要按如下方式聲明Student類:
序列化時,由Java負責從(向)流讀取(寫入)Serializable對象的細節,而你只需要將對象傳遞給(從)流,調用相應方法把對象寫入(讀取)到流中即可。
若你的類實現了Externalizable接口,可以更好地控制從流中讀取對象和寫入對象。該接口繼承了Serializable接口。聲明如下:
從流中讀取對象時,將調用readExternal()方法。將對象寫入流時,將調用writeExternal()方法。但你必須分別編寫邏輯來讀取和寫入readExternal()和writeExternal()方法中的對象字段。實現Externalizable接口的類示例如下:
下面進入序列化和反序列化的具體內容。
2.對象序列化
要序列化對象,需要執行以下步驟:
通過將ObjectInputStream類用作另一個輸入流的裝飾器來創建ObjectInputStream類的對象,該輸入流表示存儲序列化對象的存儲介質。例如,要從Student.ser文件中讀取對象,請按如下方式創建對象輸入流:
要從ByteArrayInputStream中讀取對象,請按如下方式創建對象輸出流:
使用ObjectInputStream類的readObject()方法反序列化對象,就像這樣:
注意:確保以調用writeObject()方法寫入對象相同的順序調用readObject()方法讀取對象(什么順序寫入就什么順序讀出)。例如,如果你以object-1,float和object-2順序寫入了三條信息,則必須按相同的順序讀取它們:object-1,float和object-2。
最后,關閉對象輸入流,如下所示:
清單-3演示了如何從Student.ser文件中讀取對象。確保當前目錄中存在Student.ser文件。否則,程序將打印一條錯誤消息,其中包含此文件的預期位置。
清單-3.從文件中讀取對象
輸出信息如下(和寫入的對象一致):
4.Externalizable序列化
在前面的部分中,我們介紹了如何序列化和反序列化可序列化對象。在本節中,我將向你展示如何用Externalizable序列化和反序列化(Externalizable)對象。我修改了Student類來實現Externalizable接口。我將新類命名為StudentExt,如清單-4所示。
Java將分別將對象輸出流和對象輸入流的引用傳遞給StudentExt類的writeExternal()和readExternal()方法。
在writeExternal()方法中,將name和gender字段寫入對象輸出流。請注意,height字段不會寫入對象輸出流。這意味著當你從readExternal()方法中讀取流中的對象時,將無法獲得height字段的值。writeUTF()方法用于將字符串(name和gender)寫入對象輸出流。
在readExternal()方法中,可從流中讀取name和gender字段,并在name和gender實例變量中設置它們。
清單-5和清單-6包含StudentExt對象的序列化和反序列化邏輯。
清單-5.序列化實現了Externalizable接口的StudentExt對象
運行程序輸出信息如下:
清單-6.反序列化實現了Externalizable接口的StudentExt對象
輸出結果如下:
清單-6的輸出演示了在反序列化StudentExt對象后,height字段的值是默認值(Double.NaN)。
以下是使用Externalizable接口序列化和反序列化對象的步驟:
1.當調用writeObject()方法來寫入Externalizable對象時,Java(執行引擎)會將對象的標識寫入到輸出流中,然后調用其類的writeExternal()方法。你可以在(序列化對象類的)writeExternal()方法中將與對象相關的數據寫入輸出流。如果需要,可以完全控制在此方法中寫入流的對象的相關數據。如果要存儲某些敏感數據,可能需要先將其加密,然后再將其寫入流中,并在從流中讀取數據時對其進行解密。
2.當調用readObject()方法讀取Externalizable對象時,Java會從流中讀取對象的標識。請注意,對于Externalizable對象,Java僅將對象的標識寫入到輸出流,而不是有關其類定義的任何詳細信息。Java使用對象類的no-args構造函數來創建對象。這就是你必須為一個Externalizable對象提供一個無參(no-args)構造函數的原因。它調用對象的readExternal()方法,以便在此可以完成填充或裝配對象的相關字段值。
對于Serializable對象,JVM僅序列化未聲明為瞬態的實例變量。
以上就是動力節點java培訓機構小編介紹的“實戰案例:輕松搞定Java兩種序列化機制”的內容,希望對大家有幫助,更多java最新資訊請繼續關注動力節點java培訓機構官網,每天會有精彩內容分享與你。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習