java 序列化與反序列化

什么是序列化

(1)序列化是將對象轉(zhuǎn)變?yōu)樽止?jié)序列的過程,反序列化則是將字節(jié)序列恢復為對象的過程。

(2)對象序列化保存的是對象的狀態(tài),即它的成員變量;

(3)對象的持久化存儲(寫文件),網(wǎng)絡傳輸對象,或者使用RMI都會用到對象序列化。



JAVA 提供的操作序列化的接口

(1)Java 主要提供給了兩個接口實現(xiàn)對象的序列化和反序列化,java.io.ObjectInputStream的readObject()方法?和 java.io.ObjectOutputStream 的writeObject(Object obj)方法;

(2)只有實現(xiàn)Serializable或Externalizable接口的類的對象才能被序列化;否則會拋出java.io.NotSerializableException異常。



JAVA對象序列化示例


(1)類實現(xiàn) Serializable接口

?類中未定義 writeObject(Object obj)和readObject方法,那么按照默認的序列化方式實現(xiàn)序列化和反序列化。


Student.java


Gender.java


SimpleSerializable.java

以上代碼展示了如何序列化對象到一個文件中并從文件中反序列化的過程。

序列化的過程:

首先創(chuàng)建 ObjectOutputStream 對象,該對象可以包裝其他輸出流,比如文件輸出流;

調(diào)用對象輸出流的writeObject(Object obj)方法,可以將對象寫入到輸出流中。

關閉流。結束。

對象持久化到文件中的過程結束。

反序列化的過程:

首先創(chuàng)建ObjectInputStream對象,類似于ObjectOutputStream;

調(diào)用對象輸入流的readObject()方法,讀對象到輸入流中。返回字節(jié)序列轉(zhuǎn)化的對象。

關閉流;結束。

輸出:

result



?類中定義了 writeObject(Object obj)和readObject方法,那么按照自定義的序列化方實現(xiàn)式序列化和反序列化。

在Student.java添加如下兩個方法:


user-dined_read_write_Object

輸出結果:

result2


(2)transient?關鍵字

? 當某個成員變量聲明為transient后,默認的序列化機制就會忽略該變量。

將age字段聲明為transient,

transient

輸出 age=0:

result3


此時我們可以選擇單獨傳輸某個字段;修改writeObject和readObject方法:


結果:

result4

單獨傳輸了age 字段,因此age=18;

補充:除了上面提到的兩個方法外:

private void writeObject(java.io.ObjectOutputStream out)?throws IOException ;

private void readObject(java.io.ObjectInputStream in)?throws IOException, ClassNotFoundException;

還有其他三個方法,可供我們定制自己的序列化反序列化過程:

private void readObjectNoData()?throws ObjectStreamException;

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

readObjectNoData() :用于初始化反序列化對象,當發(fā)生一些情況導致反序列化對象不能獲得數(shù)據(jù)時調(diào)用;

writeReplace() 指派其他對象寫入序列化的流中;

readResolve()返回的對象替換反序列化創(chuàng)建的實例;


readResolve() 常用于單例模式中;示例:

修改Student.java,添加instanceHoder:

Student.java


Student.java

修改SimpleSerial.java:


SimpleSerial.java

結果輸出:

result5

可以看到,s==student返回false,也就是說反序列化后得到的Student對象并不是唯一的instance,因此這樣寫單例模式是失敗的;

修正:

readResolve

再次運行:

result6


總結:

當進行序列化的時候:

首先JVM會先調(diào)用writeReplace方法,在這個階段,我們可以進行張冠李戴,將需要進行序列化的對象換成我們指定的對象.

跟著JVM將調(diào)用writeObject方法,來將對象中的屬性一個個進行序列化,我們可以在這個方法中控制住哪些屬性需要序列化.

當反序列化的時候:

JVM會調(diào)用readObject方法,將我們剛剛在writeObject方法序列化好的屬性,反序列化回來.

然后在readResolve方法中,我們也可以指定JVM返回我們特定的對象(不是剛剛序列化回來的對象).

注意到在writeReplace和readResolve,我們可以嚴格控制singleton的對象,在同一個JVM中完完全全只有唯一的對象,控制不讓singleton對象產(chǎn)生副本.


(3)類實現(xiàn)Externalizable 接口?

? ?Externalizable 接口繼承 Serializable接口:?

public interface Externalizable extends?Serializable?;

Serializable接口是一個mark interface,沒有實際方法;而Externalizable 接口提供了兩個方法:

void ?readExternal?(ObjectInput?in) ;

void ?writeExternal?(ObjectOutput?out) ;

readExternal (ObjectInput in):從輸入流中讀取內(nèi)容恢復對象;

writeExternal?(ObjectOutput?out) : 寫入對象到輸出流中;

示例:


Externalizable

使用Externalizable進行序列化時,當讀取對象時,會調(diào)用被序列化類的無參構造器去創(chuàng)建一個新的對象,然后再將被保存對象的字段的值分別填充到新對象中。因此,必須提供一個無參構造器,訪問權限為public;否則會拋出java.io.InvalidClassException 異常;

總結:Externalizable接口實現(xiàn)的功能與Serializable接口類似,Serializable序列化時不會調(diào)用默認的構造器,而Externalizable序列化時會調(diào)用默認構造器;


感謝:深入理解Java對象序列化 - 51CTO.COM

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 在Java中,我們可以通過多種方式來創(chuàng)建對象,并且只要對象沒有被回收我們都可以復用該對象。但是,我們創(chuàng)建出來的這些...
    懶癌正患者閱讀 1,672評論 0 12
  • 序列化的意義 1.永久存儲某個jvm中運行時的對象。2.對象可以網(wǎng)絡傳輸3.rmi調(diào)用都是以序列化的方式傳輸參數(shù) ...
    炫邁哥閱讀 729評論 0 0
  • 什么是序列化與反序列化 序列化是指把對象轉(zhuǎn)換為字節(jié)序列的過程(Encoding an object as a by...
    小X感悟閱讀 969評論 0 4
  • java序列化與反序列化 對象序列化是一種持久化技術,廣泛運用于網(wǎng)絡傳輸、RMI等場景中。java對象存在于JVM...
    龜龜鴨閱讀 686評論 0 0
  • 一、序列化和反序列化的概念 把對象轉(zhuǎn)換為字節(jié)序列的過程稱為對象的序列化。把字節(jié)序列恢復為對象的過程稱為對象的反序列...
    叨唧唧的閱讀 784評論 0 0

友情鏈接更多精彩內(nèi)容