本文實例講述了Java中物件序列化與反序列化。分享給大家供大家參考。具體如下:
一、簡介
物件序列化(Serializable)是指將物件轉換為位元組序列的過程,而反序列化則是根據位元組序列恢復物件的過程。
序列化一般用於以下場景:
1.永久性保存對象,保存對象的位元組序列到本地文件中;
2.透過序列化對像在網路中傳遞對象;
3.透過序列化在進程間傳遞對象。
物件所屬的類別必須實作Serializable或是Externalizable介面才能被序列化。對實現了Serializable接口的類,其序列化與反序列化採用預設的序列化方式,Externalizable接口是繼承了Serializable接口的接口,是對Serializable的擴展,實現了Externalizable接口的類完全自己控制序列化與反序列化行為。
Java.io.ObjectOutputStream代表物件輸出流,其方法writeObject(Object obj)可以實現物件的序列化,將得到的位元組序列寫入目標輸出流。
Java.io.ObjectInputStream代表物件輸入流,其readObject()方法能從來源輸入流中讀取位元組序列,將其反序列化為對象,並將其傳回。
二、序列化的幾種方式
假設定義了一個Customer類,根據Customer實現序列化方式的不同,可能有以下幾種序列化方式:
1.實作Serializable,未定義readObject和writeObject方法
ObjectOutputStream使用JDK預設方式對Customer物件的非transient的實例變數進行序列化;
ObjectInputStream使用JDK預設方式對Customer物件的非transient的實例變數進行反序列化。
2.實作Serializable,並定義了readObject和writeObject方法
ObjectOutputStream呼叫Customer類別的writeObject(ObjectOutputStream out)方法對Customer物件的非transient的實例變數進行序列化;
ObjectInputStreamStreamAustomerStream inputStream版本的調用(CustomerStream inObject(CustomerStreamInputStream)。 )方法對Customer物件的非transient的實例變數進行反序列化。
3.實作Externalizable,定義readExternal和writeExternal方法
ObjectOutputStream呼叫Customer類別的writeExternal方法對Customer物件的非transient實例變數進行序列化;
ObjectInputStream首先透過Customer物件類別的無物件函數進行一個序列化;用readExternal方法對Customer物件的非transient實例變數進行反序列化。
三、Serializable介面
類別透過實作 java.io.Serializable 介面以啟用其序列化功能。未實作此介面的類別將無法使其任何狀態序列化或反序列化。可序列化類別的所有子類型本身都是可序列化的。序列化介面沒有方法或字段,僅用於標識可序列化的語義。
在反序列化過程中,將使用該類別的公用或受保護的無參數建構方法初始化不可序列化類別的欄位。可序列化的子類別必須能夠存取無參數構造方法。可序列化子類別的欄位將從該流中恢復。
當遍歷一個類別視圖時,可能會遇到不支援 Serializable 介面的物件。在此情況下,將拋出 NotSerializableException,並將標識不可序列化物件的類別。
1.準確簽名
在序列化和反序列化過程中需要特殊處理的類別必須使用下列準確簽名來實現特殊方法:
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 方法負責寫入特定類別的物件的狀態,以便將它還原為對應的。透過呼叫 out.defaultWriteObject 可以呼叫保存 Object 的欄位的預設機制。該方法本身不需要涉及屬於其超類別或子類別的狀態。透過使用 writeObject 方法或使用 DataOutput 支援的用於基本資料類型的方法將各個欄位寫入 ObjectOutputStream,狀態可以被保存。
readObject 方法負責從流中讀取並還原類別欄位。它可以呼叫 in.defaultReadObject 來呼叫預設機制,以還原物件的非靜態和非瞬態欄位。 defaultReadObject 方法使用流中的資訊來指派流中透過目前物件中對應指定欄位所儲存的物件的欄位。這用於處理類別演化後需要新增欄位的情況。該方法本身不需要涉及屬於其超類別或子類別的狀態。透過使用 writeObject 方法或使用 DataOutput 支援的用於基本資料類型的方法將各個欄位寫入 ObjectOutputStream,狀態可以被保存。
在序列化流不列出給定類別作為將被反序列化物件的超類別的情況下,readObjectNoData 方法負責初始化特定類別的物件狀態。這在接收方使用的反序列化實例類別的版本不同於發送方,且接收者版本擴展的類別不是發送者版本擴展的類別時發生。在序列化流已經被篡改時也將發生;因此,不管源流是「敵意的」還是不完整的,readObjectNoData 方法都可以用來正確地初始化反序列化的物件。
將物件寫入流時需要指定要使用的替代物件的可序列化類,應使用準確的簽章來實作此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
此writeReplace方法將由序列化調用,前提是如果此方法存在,而且它可以透過被序列化物件的類別中定義的一個方法來存取。因此,此方法可以擁有私有 (private)、受保護的(protected) 和套件私有 (package-private) 存取。子類別對此方法的存取遵循 java 存取規則。
在從流中讀取類別的一個實例時需要指定替代的類別應使用的準確簽章來實作此特殊方法。
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此readResolve方法遵循與writeReplace相同的呼叫規則和存取規則。
如果一個類別定義了readResolve方法,那麼在反序列化的最後將呼叫readResolve方法,該方法傳回的物件為反序列化的最終結果。
2.serialVersionUID
序列化運行時使用一個稱為serialVersionUID 的版本號與每個可序列化類別相關聯,該序號在反序列化過程中用於驗證序列化物件的發送者和接收者是否為該物件載入了與序列化相容的類別。如果接收者載入的該物件的類別的 serialVersionUID 與對應的發送者的類別的版本號碼不同,則反序列化將會導致 InvalidClassException。可序列化類別可以透過宣告名為"serialVersionUID" 的欄位(此欄位必須是靜態(static)、最終(final) 的long 型欄位)明確宣告其自己的serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化類別未明確聲明serialVersionUID,則序列化運行時將基於該類別的各個方面計算該類別的預設serialVersionUID 值,如“Java(TM) 物件序列化規範”中所述。不過,強烈建議所有可序列化類別都明確聲明serialVersionUID 值,原因是計算預設的serialVersionUID 對類別的詳細資訊具有較高的敏感性,根據編譯器實現的不同可能千差萬別,這樣在反序列化過程中可能會導致意外的InvalidClassException。因此,為確保 serialVersionUID 值跨不同 java 編譯器實現的一致性,序列化類別必須宣告一個明確的 serialVersionUID 值。也強烈建議使用 private 修飾符顯示聲明 serialVersionUID(如果可能),原因是這種聲明僅應用於直接聲明類別 -- serialVersionUID 欄位作為繼承成員沒有用處。陣列類別不能宣告一個明確的 serialVersionUID,因此它們總是具有預設的計算值,但是陣列類別沒有符合 serialVersionUID 值的要求。
3.Externalizable介面
Externalizable是Serailizable的擴展,實現Externalizable介面的類別其序列化有以下特點:
序列化時呼叫類別的方法writeExternal,反序列化呼叫readExternal方法;
序列化時呼叫類別的方法writeExternal,反序列化呼叫readExternal方法;
1.直接對物件的不宜對外公開的敏感資料進行序列化,這是不安全的;
2.不會檢查物件的成員變數是否符合正確的約束條件,有可能被篡改資料而導致運行異常;
3.需要對物件圖做遞歸遍歷,如果物件圖很複雜,會消耗很多資源,設定引起Java虛擬機的堆疊溢出;

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 Linux新版
SublimeText3 Linux最新版

Dreamweaver CS6
視覺化網頁開發工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。