Java序列化详解
以前在使用hibernate時(shí)候,domain域模型的JavaBean總提示實(shí)現(xiàn)序列化接口,生成序列化得ID:static final long serialVersionUID = 42L;
不明白是什么意思。今天在網(wǎng)上查了查有點(diǎn)明白了。
?
序列化是什么:
序列化就是將一個(gè)對(duì)象的狀態(tài)(各個(gè)屬性量)保存起來(lái),然后在適當(dāng)?shù)臅r(shí)候再獲得。
序列化分為兩大部分:序列化和反序列化。序列化是這個(gè)過(guò)程的第一部分,將數(shù)據(jù)分解成字節(jié)流,以便存儲(chǔ)在文件中或在網(wǎng)絡(luò)上傳輸。反序列化就是打開(kāi)字節(jié)流并重構(gòu)對(duì)象。對(duì)象序列化不僅要將基本數(shù)據(jù)類(lèi)型轉(zhuǎn)換成字節(jié)表示,有時(shí)還要恢復(fù)數(shù)據(jù)。恢復(fù)數(shù)據(jù)要求有恢復(fù)數(shù)據(jù)的對(duì)象實(shí)例
序列化的什么特點(diǎn):
如果某個(gè)類(lèi)能夠被序列化,其子類(lèi)也可以被序列化。聲明為static和transient類(lèi)型的成員數(shù)據(jù)不能被序列化。因?yàn)閟tatic代表類(lèi)的狀態(tài), transient代表對(duì)象的臨時(shí)數(shù)據(jù)。
什么時(shí)候使用序列化:
一:對(duì)象序列化可以實(shí)現(xiàn)分布式對(duì)象。主要應(yīng)用例如:RMI要利用對(duì)象序列化運(yùn)行遠(yuǎn)程主機(jī)上的服務(wù),就像在本地機(jī)上運(yùn)行對(duì)象時(shí)一樣。
二:java對(duì)象序列化不僅保留一個(gè)對(duì)象的數(shù)據(jù),而且遞歸保存對(duì)象引用的每個(gè)對(duì)象的數(shù)據(jù)。可以將整個(gè)對(duì)象層次寫(xiě)入字節(jié)流中,可以保存在文件中或在網(wǎng)絡(luò)連接上傳遞。利用對(duì)象序列化可以進(jìn)行對(duì)象的"深復(fù)制",即復(fù)制對(duì)象本身及引用的對(duì)象本身。序列化一個(gè)對(duì)象可能得到整個(gè)對(duì)象序列。
======================
可以看看接口java.io.serializable的中文解釋:
Serializable
public interface Serializable
類(lèi)通過(guò)實(shí)現(xiàn) java.io.Serializable 接口以啟用其序列化功能。未實(shí)現(xiàn)此接口的類(lèi)將無(wú)法使其任何狀態(tài)序列化或反序列化。可序列化類(lèi)的所有子類(lèi)型本身都是可序列化的。序列化接口沒(méi)有方法或字段,僅用于標(biāo)識(shí)可序列化的語(yǔ)義。
要允許不可序列化類(lèi)的子類(lèi)型序列化,可以假定該子類(lèi)型負(fù)責(zé)保存和還原超類(lèi)型的公用 (public)、受保護(hù)的 (protected) 和(如果可訪問(wèn))包 (package) 字段的狀態(tài)。僅在子類(lèi)型擴(kuò)展的類(lèi)有一個(gè)可訪問(wèn)的無(wú)參數(shù)構(gòu)造方法來(lái)初始化該類(lèi)的狀態(tài)時(shí),才可以假定子類(lèi)型有此責(zé)任。如果不是這種情況,則聲明一個(gè)類(lèi)為可序列化類(lèi)是錯(cuò)誤的。該錯(cuò)誤將在運(yùn)行時(shí)檢測(cè)到。
在反序列化過(guò)程中,將使用該類(lèi)的公用或受保護(hù)的無(wú)參數(shù)構(gòu)造方法初始化不可序列化類(lèi)的字段。可序列化的子類(lèi)必須能夠訪問(wèn)無(wú)參數(shù)的構(gòu)造方法。可序列化子類(lèi)的字段將從該流中還原。
當(dāng)遍歷一個(gè)圖形時(shí),可能會(huì)遇到不支持可序列化接口的對(duì)象。在此情況下,將拋出 NotSerializableException,并將標(biāo)識(shí)不可序列化對(duì)象的類(lèi)。
在序列化和反序列化過(guò)程中需要特殊處理的類(lèi)必須使用下列準(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;
writeObject 方法負(fù)責(zé)寫(xiě)入特定類(lèi)的對(duì)象的狀態(tài),以便相應(yīng)的 readObject 方法可以還原它。通過(guò)調(diào)用 out.defaultWriteObject 可以調(diào)用保存 Object 的字段的默認(rèn)機(jī)制。該方法本身不需要涉及屬于其超類(lèi)或子類(lèi)的狀態(tài)。狀態(tài)是通過(guò)使用 writeObject 方法或使用 DataOutput 支持的用于基本數(shù)據(jù)類(lèi)型的方法將各個(gè)字段寫(xiě)入 ObjectOutputStream 來(lái)保存的。
readObject 方法負(fù)責(zé)從流中讀取并還原類(lèi)字段。它可以調(diào)用 in.defaultReadObject 來(lái)調(diào)用默認(rèn)機(jī)制,以還原對(duì)象的非靜態(tài)和非瞬態(tài)字段。defaultReadObject 方法使用流中的信息來(lái)分配流中通過(guò)當(dāng)前對(duì)象中相應(yīng)命名字段保存的對(duì)象的字段。這用于處理類(lèi)發(fā)展后需要添加新字段的情形。該方法本身不需要涉及屬于其超類(lèi)或子類(lèi)的狀態(tài)。狀態(tài)是通過(guò)使用 writeObject 方法或使用 DataOutput 支持的用于基本數(shù)據(jù)類(lèi)型的方法將各個(gè)字段寫(xiě)入 ObjectOutputStream 來(lái)保存的。
將對(duì)象寫(xiě)入流時(shí)需要指定要使用的替代對(duì)象的可序列化類(lèi),應(yīng)使用準(zhǔn)確的簽名來(lái)實(shí)現(xiàn)此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
此 writeReplace 方法將由序列化調(diào)用,前提是如果此方法存在,而且它可以通過(guò)被序列化對(duì)象的類(lèi)中定義的一個(gè)方法訪問(wèn)。因此,該方法可以擁有私有 (private)、受保護(hù)的 (protected) 和包私有 (package-private) 訪問(wèn)。子類(lèi)對(duì)此方法的訪問(wèn)遵循 java 訪問(wèn)規(guī)則。
在從流中讀取類(lèi)的一個(gè)實(shí)例時(shí)需要指定替代的類(lèi)應(yīng)使用的準(zhǔn)確簽名來(lái)實(shí)現(xiàn)此特殊方法。
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此 readResolve 方法遵循與 writeReplace 相同的調(diào)用規(guī)則和訪問(wèn)規(guī)則。
序列化運(yùn)行時(shí)使用一個(gè)稱(chēng)為 serialVersionUID 的版本號(hào)與每個(gè)可序列化類(lèi)相關(guān)聯(lián),該序列號(hào)在反序列化過(guò)程中用于驗(yàn)證序列化對(duì)象的發(fā)送者和接收者是否為該對(duì)象加載了與序列化兼容的類(lèi)。如果接收者加載的該對(duì)象的類(lèi)的 serialVersionUID 與對(duì)應(yīng)的發(fā)送者的類(lèi)的版本號(hào)不同,則反序列化將會(huì)導(dǎo)致 InvalidClassException。可序列化類(lèi)可以通過(guò)聲明名為 "serialVersionUID" 的字段(該字段必須是靜態(tài) (static)、最終 (final) 的 long 型字段)顯式聲明其自己的 serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化類(lèi)未顯式聲明 serialVersionUID,則序列化運(yùn)行時(shí)將基于該類(lèi)的各個(gè)方面計(jì)算該類(lèi)的默認(rèn) serialVersionUID 值,如“Java(TM) 對(duì)象序列化規(guī)范”中所述。不過(guò),強(qiáng)烈建議 所有可序列化類(lèi)都顯式聲明 serialVersionUID 值,原因計(jì)算默認(rèn)的 serialVersionUID 對(duì)類(lèi)的詳細(xì)信息具有較高的敏感性,根據(jù)編譯器實(shí)現(xiàn)的不同可能千差萬(wàn)別,這樣在反序列化過(guò)程中可能會(huì)導(dǎo)致意外的 InvalidClassException。因此,為保證 serialVersionUID 值跨不同 java 編譯器實(shí)現(xiàn)的一致性,序列化類(lèi)必須聲明一個(gè)明確的 serialVersionUID 值。還強(qiáng)烈建議使用 private 修改器顯示聲明 serialVersionUID(如果可能),原因是這種聲明僅應(yīng)用于立即聲明類(lèi) -- serialVersionUID 字段作為繼承成員沒(méi)有用處。
java.io.Serializable引發(fā)的問(wèn)題——什么是序列化?在什么情況下將類(lèi)序列化?
序列化就是一種用來(lái)處理對(duì)象流的機(jī)制,所謂對(duì)象流也就是將對(duì)象的內(nèi)容進(jìn)行流化。可以對(duì)流化后的對(duì)象進(jìn)行讀寫(xiě)操作,也可將流化后的對(duì)象傳輸于網(wǎng)絡(luò)之間。序列化是為了解決在對(duì)對(duì)象流進(jìn)行讀寫(xiě)操作時(shí)所引發(fā)的問(wèn)題。序列化的實(shí)現(xiàn):將需要被序列化的類(lèi)實(shí)現(xiàn)Serializable接口,該接口沒(méi)有需要實(shí)現(xiàn)的方法,implements?Serializable只是為了標(biāo)注該對(duì)象是可被序列化的,然后使用一個(gè)輸出流(如:FileOutputStream)來(lái)構(gòu)造一個(gè)ObjectOutputStream(對(duì)象流)對(duì)象,接著,使用ObjectOutputStream對(duì)象的writeObject(Object obj)方法就可以將參數(shù)為obj的對(duì)象寫(xiě)出(即保存其狀態(tài)),要恢復(fù)的話則用輸入流。
序列化:序列化是將對(duì)象轉(zhuǎn)換為容易傳輸?shù)母袷降倪^(guò)程。例如,可以序列化一個(gè)對(duì)象,然后使用 HTTP 通過(guò) Internet 在客戶(hù)端和服務(wù)器之間傳輸該對(duì)象。在另一端,反序列化將從該流重新構(gòu)造對(duì)象。
是對(duì)象永久化的一種機(jī)制。
?確切的說(shuō)應(yīng)該是對(duì)象的序列化,一般程序在運(yùn)行時(shí),產(chǎn)生對(duì)象,這些對(duì)象隨著程序的停止運(yùn)行而消失,但如果我們想把某些對(duì)象(因?yàn)槭菍?duì)象,所以有各自不同的特性)保存下來(lái),在程序終止運(yùn)行后,這些對(duì)象仍然存在,可以在程序再次運(yùn)行時(shí)讀取這些對(duì)象的值,或者在其他程序中利用這些保存下來(lái)的對(duì)象。這種情況下就要用到對(duì)象的序列化。
只有序列化的對(duì)象才可以存儲(chǔ)在存儲(chǔ)設(shè)備上。為了對(duì)象的序列化而需要繼承的接口也只是一個(gè)象征性的接口而已,也就是說(shuō)繼承這個(gè)接口說(shuō)明這個(gè)對(duì)象可以被序列化了,沒(méi)有其他的目的。之所以需要對(duì)象序列化,是因?yàn)橛袝r(shí)候?qū)ο笮枰诰W(wǎng)絡(luò)上傳輸,傳輸?shù)臅r(shí)候需要這種序列化處理,從服務(wù)器硬盤(pán)上把序列化的對(duì)象取出,然后通過(guò)網(wǎng)絡(luò)傳到客戶(hù)端,再由客戶(hù)端把序列化的對(duì)象讀入內(nèi)存,執(zhí)行相應(yīng)的處理。
對(duì)象序列化是java的一個(gè)特征,通過(guò)該特征可以將對(duì)象寫(xiě)作一組字節(jié)碼,當(dāng)在其他位置讀到這些字節(jié)碼時(shí),可以依此創(chuàng)建一個(gè)新的對(duì)象,而且新對(duì)象的狀態(tài)與原對(duì)象完全相同。為了實(shí)現(xiàn)對(duì)象序列化,要求必須能夠訪問(wèn)類(lèi)的私有變量,從而保證對(duì)象狀態(tài)能夠正確的得以保存和恢復(fù)。相應(yīng)的,對(duì)象序列化API能夠在對(duì)象重建時(shí),將這些值還原給私有的數(shù)據(jù)成員。這是對(duì)java語(yǔ)言訪問(wèn)權(quán)限的挑戰(zhàn)。通常用在服務(wù)器客戶(hù)端的對(duì)象交換上面,另外就是在本機(jī)的存儲(chǔ)。
對(duì)象序列化的最主要的用處就是在傳遞,和保存對(duì)象(object)的時(shí)候,保證對(duì)象的完整性和可傳遞性。譬如通過(guò)網(wǎng)絡(luò)傳輸,或者把一個(gè)對(duì)象保存成一個(gè)文件的時(shí)候,要實(shí)現(xiàn)序列化接口 。
*
Quote:
比較java.io.Externalizable和java.io.Serializable
[URL]http://www.zdnet.com.cn/developer/code/story/0,3800066897,39304080,00.htm[/URL]
即使你沒(méi)有用過(guò)對(duì)象序列化(serialization),你可能也知道它。但你是否知道?Java?還支持另外一種形式的對(duì)象持久化,外部化(externalization)?
下面是序列化和外部化在代碼級(jí)的關(guān)聯(lián)方式:
public interface?Serializable?{}
public interface Externalizable extends?Serializable?{
void readExternal(ObjectInput in);
void writeExternal(ObjectOutput out);
}
序列化和外部化的主要區(qū)別
外部化和序列化是實(shí)現(xiàn)同一目標(biāo)的兩種不同方法。下面讓我們分析一下序列化和外部化之間的主要區(qū)別。
通過(guò)Serializable接口對(duì)對(duì)象序列化的支持是內(nèi)建于核心 API 的,但是java.io.Externalizable的所有實(shí)現(xiàn)者必須提供讀取和寫(xiě)出的實(shí)現(xiàn)。Java?已經(jīng)具有了對(duì)序列化的內(nèi)建支持,也就是說(shuō)只要制作自己的類(lèi)java.io.Serializable,Java?就會(huì)試圖存儲(chǔ)和重組你的對(duì)象。如果使用外部化,你就可以選擇完全由自己完成讀取和寫(xiě)出的工作,Java?對(duì)外部化所提供的唯一支持是接口:
voidreadExternal(ObjectInput in)
void writeExternal(ObjectOutput out)
現(xiàn)在如何實(shí)現(xiàn)readExternal() 和writeExternal() 就完全看你自己了。
序列化會(huì)自動(dòng)存儲(chǔ)必要的信息,用以反序列化被存儲(chǔ)的實(shí)例,而外部化則只保存被存儲(chǔ)的類(lèi)的標(biāo)識(shí)。當(dāng)你通過(guò)java.io.Serializable接口序列化一個(gè)對(duì)象時(shí),有關(guān)類(lèi)的信息,比如它的屬性和這些屬性的類(lèi)型,都與實(shí)例數(shù)據(jù)一起被存儲(chǔ)起來(lái)。在選擇走Externalizable這條路時(shí),Java?只存儲(chǔ)有關(guān)每個(gè)被存儲(chǔ)類(lèi)型的非常少的信息。
每個(gè)接口的優(yōu)點(diǎn)和缺點(diǎn)
Serializable接口
· 優(yōu)點(diǎn):內(nèi)建支持
· 優(yōu)點(diǎn):易于實(shí)現(xiàn)
· 缺點(diǎn):占用空間過(guò)大
· 缺點(diǎn):由于額外的開(kāi)銷(xiāo)導(dǎo)致速度變比較慢
Externalizable接口
· 優(yōu)點(diǎn):開(kāi)銷(xiāo)較少(程序員決定存儲(chǔ)什么)
· 優(yōu)點(diǎn):可能的速度提升
· 缺點(diǎn):虛擬機(jī)不提供任何幫助,也就是說(shuō)所有的工作都落到了開(kāi)發(fā)人員的肩上。
在兩者之間如何選擇要根據(jù)應(yīng)用程序的需求來(lái)定。Serializable通常是最簡(jiǎn)單的解決方案,但是它可能會(huì)導(dǎo)致出現(xiàn)不可接受的性能問(wèn)題或空間問(wèn)題;在出現(xiàn)這些問(wèn)題的情況下,Externalizable可能是一條可行之路。
要記住一點(diǎn),如果一個(gè)類(lèi)是可外部化的(Externalizable),那么Externalizable方法將被用于序列化類(lèi)的實(shí)例,即使這個(gè)類(lèi)型提供了Serializable方法:
private void writeObject()
private void readObject()
總結(jié)
- 上一篇: 帧同步~平滑处理
- 下一篇: hibernate+mysql保存中文数