亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中對(duì)象序列化與反序列化詳解

 更新時(shí)間:2015年09月09日 10:00:19   作者:異次元藍(lán)客  
這篇文章主要介紹了Java中對(duì)象序列化與反序列化,較為詳細(xì)的分析了java中對(duì)象序列化的概念、原理、實(shí)現(xiàn)方法及相關(guān)注意事項(xiàng),具有一定參考借鑒價(jià)值,需要的朋友可以參考下

本文實(shí)例講述了Java中對(duì)象序列化與反序列化。分享給大家供大家參考。具體如下:

一、簡(jiǎn)介

對(duì)象序列化(Serializable)是指將對(duì)象轉(zhuǎn)換為字節(jié)序列的過(guò)程,而反序列化則是根據(jù)字節(jié)序列恢復(fù)對(duì)象的過(guò)程。

序列化一般用于以下場(chǎng)景:

1.永久性保存對(duì)象,保存對(duì)象的字節(jié)序列到本地文件中;
2.通過(guò)序列化對(duì)象在網(wǎng)絡(luò)中傳遞對(duì)象;
3.通過(guò)序列化在進(jìn)程間傳遞對(duì)象。

對(duì)象所屬的類必須實(shí)現(xiàn)Serializable或是Externalizable接口才能被序列化。對(duì)實(shí)現(xiàn)了Serializable接口的類,其序列化與反序列化采用默認(rèn)的序列化方式,Externalizable接口是繼承了Serializable接口的接口,是對(duì)Serializable的擴(kuò)展,實(shí)現(xiàn)了Externalizable接口的類完全自己控制序列化與反序列化行為。

Java.io.ObjectOutputStream代表對(duì)象輸出流,其方法writeObject(Object obj)可以實(shí)現(xiàn)對(duì)象的序列化,將得到的字節(jié)序列寫到目標(biāo)輸出流中。

Java.io.ObjectInputStream代表對(duì)象輸入流,其readObject()方法能從源輸入流中讀取字節(jié)序列,將其反序列化為對(duì)象,并將其返回。

二、序列化的幾種方式

假設(shè)定義了一個(gè)Customer類,根據(jù)Customer實(shí)現(xiàn)序列化方式的不同,可能有以下幾種序列化方式:

1.實(shí)現(xiàn)Serializable,未定義readObject和writeObject方法

ObjectOutputStream使用JDK默認(rèn)方式對(duì)Customer對(duì)象的非transient的實(shí)例變量進(jìn)行序列化;
ObjectInputStream使用JDK默認(rèn)方式對(duì)Customer對(duì)象的非transient的實(shí)例變量進(jìn)行反序列化。

2.實(shí)現(xiàn)Serializable,并定義了readObject和writeObject方法

ObjectOutputStream調(diào)用Customer類的writeObject(ObjectOutputStream out)方法對(duì)Customer對(duì)象的非transient的實(shí)例變量進(jìn)行序列化;
ObjectInputStream調(diào)用Customer類的readObject(ObjectInputStream in)方法對(duì)Customer對(duì)象的非transient的實(shí)例變量進(jìn)行反序列化。

3.實(shí)現(xiàn)Externalizable,定義readExternal和writeExternal方法

ObjectOutputStream調(diào)用Customer類的writeExternal方法對(duì)Customer對(duì)象的非transient實(shí)例變量進(jìn)行序列化;
ObjectInputStream首先通過(guò)Customer類的無(wú)參數(shù)構(gòu)造函數(shù)實(shí)例化一個(gè)對(duì)象,再用readExternal方法對(duì)Customer對(duì)象的非transient實(shí)例變量進(jìn)行反序列化。

三、Serializable接口

類通過(guò)實(shí)現(xiàn) java.io.Serializable 接口以啟用其序列化功能。未實(shí)現(xiàn)此接口的類將無(wú)法使其任何狀態(tài)序列化或反序列化??尚蛄谢惖乃凶宇愋捅旧矶际强尚蛄谢?。序列化接口沒(méi)有方法或字段,僅用于標(biāo)識(shí)可序列化的語(yǔ)義。

在反序列化過(guò)程中,將使用該類的公用或受保護(hù)的無(wú)參數(shù)構(gòu)造方法初始化不可序列化類的字段??尚蛄谢淖宇惐仨毮軌蛟L問(wèn)無(wú)參數(shù)構(gòu)造方法??尚蛄谢宇惖淖侄螌脑摿髦谢謴?fù)。

當(dāng)遍歷一個(gè)類視圖時(shí),可能會(huì)遇到不支持 Serializable 接口的對(duì)象。在此情況下,將拋出 NotSerializableException,并將標(biāo)識(shí)不可序列化對(duì)象的類。

1.準(zhǔn)確簽名

在序列化和反序列化過(guò)程中需要特殊處理的類必須使用下列準(zhǔn)確簽名來(lái)實(shí)現(xiàn)特殊方法:

private void writeObject(java.io.ObjectOutputStream out) throws IOException
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;

writeObject 方法負(fù)責(zé)寫入特定類的對(duì)象的狀態(tài),以便相應(yīng)的 readObject 方法可以恢復(fù)它。通過(guò)調(diào)用 out.defaultWriteObject 可以調(diào)用保存 Object 的字段的默認(rèn)機(jī)制。該方法本身不需要涉及屬于其超類或子類的狀態(tài)。通過(guò)使用 writeObject 方法或使用 DataOutput 支持的用于基本數(shù)據(jù)類型的方法將各個(gè)字段寫入 ObjectOutputStream,狀態(tài)可以被保存。

readObject 方法負(fù)責(zé)從流中讀取并恢復(fù)類字段。它可以調(diào)用 in.defaultReadObject 來(lái)調(diào)用默認(rèn)機(jī)制,以恢復(fù)對(duì)象的非靜態(tài)和非瞬態(tài)字段。defaultReadObject 方法使用流中的信息來(lái)分配流中通過(guò)當(dāng)前對(duì)象中相應(yīng)指定字段保存的對(duì)象的字段。這用于處理類演化后需要添加新字段的情形。該方法本身不需要涉及屬于其超類或子類的狀態(tài)。通過(guò)使用 writeObject 方法或使用 DataOutput 支持的用于基本數(shù)據(jù)類型的方法將各個(gè)字段寫入 ObjectOutputStream,狀態(tài)可以被保存。

在序列化流不列出給定類作為將被反序列化對(duì)象的超類的情況下,readObjectNoData 方法負(fù)責(zé)初始化特定類的對(duì)象狀態(tài)。這在接收方使用的反序列化實(shí)例類的版本不同于發(fā)送方,并且接收者版本擴(kuò)展的類不是發(fā)送者版本擴(kuò)展的類時(shí)發(fā)生。在序列化流已經(jīng)被篡改時(shí)也將發(fā)生;因此,不管源流是“敵意的”還是不完整的,readObjectNoData 方法都可以用來(lái)正確地初始化反序列化的對(duì)象。

將對(duì)象寫入流時(shí)需要指定要使用的替代對(duì)象的可序列化類,應(yīng)使用準(zhǔn)確的簽名來(lái)實(shí)現(xiàn)此特殊方法:

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
此writeReplace方法將由序列化調(diào)用,前提是如果此方法存在,而且它可以通過(guò)被序列化對(duì)象的類中定義的一個(gè)方法訪問(wèn)。因此,該方法可以擁有私有 (private)、受保護(hù)的(protected) 和包私有 (package-private) 訪問(wèn)。子類對(duì)此方法的訪問(wèn)遵循 java 訪問(wèn)規(guī)則。

在從流中讀取類的一個(gè)實(shí)例時(shí)需要指定替代的類應(yīng)使用的準(zhǔn)確簽名來(lái)實(shí)現(xiàn)此特殊方法。

ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此readResolve方法遵循與writeReplace相同的調(diào)用規(guī)則和訪問(wèn)規(guī)則。
如果一個(gè)類定義了readResolve方法,那么在反序列化的最后將調(diào)用readResolve方法,該方法返回的對(duì)象為反序列化的最終結(jié)果。

2.serialVersionUID

序列化運(yùn)行時(shí)使用一個(gè)稱為 serialVersionUID 的版本號(hào)與每個(gè)可序列化類相關(guān)聯(lián),該序列號(hào)在反序列化過(guò)程中用于驗(yàn)證序列化對(duì)象的發(fā)送者和接收者是否為該對(duì)象加載了與序列化兼容的類。如果接收者加載的該對(duì)象的類的 serialVersionUID 與對(duì)應(yīng)的發(fā)送者的類的版本號(hào)不同,則反序列化將會(huì)導(dǎo)致 InvalidClassException??尚蛄谢惪梢酝ㄟ^(guò)聲明名為 "serialVersionUID" 的字段(該字段必須是靜態(tài) (static)、最終 (final) 的 long 型字段)顯式聲明其自己的 serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化類未顯式聲明 serialVersionUID,則序列化運(yùn)行時(shí)將基于該類的各個(gè)方面計(jì)算該類的默認(rèn) serialVersionUID 值,如“Java(TM) 對(duì)象序列化規(guī)范”中所述。不過(guò),強(qiáng)烈建議 所有可序列化類都顯式聲明 serialVersionUID 值,原因是計(jì)算默認(rèn)的 serialVersionUID 對(duì)類的詳細(xì)信息具有較高的敏感性,根據(jù)編譯器實(shí)現(xiàn)的不同可能千差萬(wàn)別,這樣在反序列化過(guò)程中可能會(huì)導(dǎo)致意外的 InvalidClassException。因此,為保證 serialVersionUID 值跨不同 java 編譯器實(shí)現(xiàn)的一致性,序列化類必須聲明一個(gè)明確的 serialVersionUID 值。還強(qiáng)烈建議使用 private 修飾符顯示聲明 serialVersionUID(如果可能),原因是這種聲明僅應(yīng)用于直接聲明類 -- serialVersionUID 字段作為繼承成員沒(méi)有用處。數(shù)組類不能聲明一個(gè)明確的 serialVersionUID,因此它們總是具有默認(rèn)的計(jì)算值,但是數(shù)組類沒(méi)有匹配 serialVersionUID 值的要求。

3.Externalizable接口

Externalizable是Serailizable的擴(kuò)展,實(shí)現(xiàn)Externalizable接口的類其序列化有以下特點(diǎn):
序列化時(shí)調(diào)用類的方法writeExternal,反序列化調(diào)用readExternal方法;
在執(zhí)行反序列化時(shí)先調(diào)用類的無(wú)參數(shù)構(gòu)造函數(shù),這一點(diǎn)與默認(rèn)的反序列化是不同的,因此對(duì)實(shí)現(xiàn)Externalizable接口來(lái)實(shí)現(xiàn)序列化的類而言,必須提供一個(gè)public的無(wú)參數(shù)構(gòu)造函數(shù),否則在反序列化時(shí)將出現(xiàn)異常。

四、總結(jié)

如果采用默認(rèn)的序列化方式,只要讓一個(gè)類實(shí)現(xiàn)Serializable接口,其實(shí)例就可以被序列化。通常,專門為繼承而設(shè)計(jì)的類應(yīng)該盡量不要實(shí)現(xiàn)Serializable接口,因?yàn)橐坏└割悓?shí)現(xiàn)了Serializable接口,其所有子類也都是可序列化的了。

默認(rèn)的序列化方式的不足之處:

1.直接對(duì)對(duì)象的不宜對(duì)外公開的敏感數(shù)據(jù)進(jìn)行序列化,這是不安全的;
2.不會(huì)檢查對(duì)象的成員變量是否符合正確的約束條件,有可能被篡改數(shù)據(jù)而導(dǎo)致運(yùn)行異常;
3.需要對(duì)對(duì)象圖做遞歸遍歷,如果對(duì)象圖很復(fù)雜,會(huì)消耗很多資源,設(shè)置引起Java虛擬機(jī)的堆棧溢出;
4.使類的接口被類的內(nèi)部實(shí)現(xiàn)約束,制約類的升級(jí)與維護(hù)。

通過(guò)實(shí)現(xiàn)Serializable接口的private類型的writeObject()和readObject(),或是實(shí)現(xiàn)Externalizable接口,并實(shí)現(xiàn)writeExternal()與readExternal()方法,并提供public類型的無(wú)參數(shù)構(gòu)造函數(shù)兩種方式來(lái)控制序列化過(guò)程可以有效規(guī)避默認(rèn)序列化方式的不足之處。

希望本文所述對(duì)大家的java程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Java經(jīng)典設(shè)計(jì)模式之策略模式原理與用法詳解

    Java經(jīng)典設(shè)計(jì)模式之策略模式原理與用法詳解

    這篇文章主要介紹了Java經(jīng)典設(shè)計(jì)模式之策略模式,簡(jiǎn)單說(shuō)明了策略模式的概念、原理并結(jié)合實(shí)例形式分析了java策略模式的具有用法與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-08-08
  • Java并發(fā)編程之閉鎖與柵欄的實(shí)現(xiàn)

    Java并發(fā)編程之閉鎖與柵欄的實(shí)現(xiàn)

    這篇文章主要介紹了Java并發(fā)編程之閉鎖與柵欄的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • java打包maven啟動(dòng)報(bào)錯(cuò)jar中沒(méi)有主清單屬性

    java打包maven啟動(dòng)報(bào)錯(cuò)jar中沒(méi)有主清單屬性

    本文主要介紹了java打包maven啟動(dòng)報(bào)錯(cuò)jar中沒(méi)有主清單屬性,可能原因是創(chuàng)建springboot項(xiàng)目時(shí),自動(dòng)導(dǎo)入,下面就來(lái)介紹一下解決方法,感興趣的可以了解一下
    2024-03-03
  • spring?cloud之eureka高可用集群和服務(wù)分區(qū)解析

    spring?cloud之eureka高可用集群和服務(wù)分區(qū)解析

    這篇文章主要介紹了spring?cloud之eureka高可用集群和服務(wù)分區(qū)解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Spring之關(guān)于PropertyDescriptor的擴(kuò)展剖析

    Spring之關(guān)于PropertyDescriptor的擴(kuò)展剖析

    這篇文章主要介紹了Spring之關(guān)于PropertyDescriptor的擴(kuò)展剖析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java long 轉(zhuǎn)成 String的實(shí)現(xiàn)

    Java long 轉(zhuǎn)成 String的實(shí)現(xiàn)

    這篇文章主要介紹了Java long 轉(zhuǎn)成 String的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • 通過(guò)實(shí)例了解java TransferQueue

    通過(guò)實(shí)例了解java TransferQueue

    這篇文章主要介紹了TransferQueue實(shí)例,下面小編和大家一起來(lái)學(xué)習(xí)一下
    2019-05-05
  • Maven發(fā)布項(xiàng)目 (jar包) 到Nexus私服中的操作

    Maven發(fā)布項(xiàng)目 (jar包) 到Nexus私服中的操作

    這篇文章主要介紹了Maven發(fā)布項(xiàng)目 (jar包) 到Nexus私服中的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • Spring高階用法之自定義業(yè)務(wù)對(duì)象組件化

    Spring高階用法之自定義業(yè)務(wù)對(duì)象組件化

    這篇文章主要介紹了Spring高階用法之自定義業(yè)務(wù)對(duì)象組件化,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • JavaGUI事件監(jiān)聽(tīng)機(jī)制超詳細(xì)講解

    JavaGUI事件監(jiān)聽(tīng)機(jī)制超詳細(xì)講解

    Java事件監(jiān)聽(tīng)器是由事件類和監(jiān)聽(tīng)接口組成,自定義一個(gè)事件前,必須提供一個(gè)事件的監(jiān)聽(tīng)接口以及一個(gè)事件類。JAVA中監(jiān)聽(tīng)接口是繼承java.util.EventListener的類,事件類繼承java.util.EventObject的類
    2023-03-03

最新評(píng)論