最近在閱讀Core J2EE Patterns 的時候發現例子裡用於在各個層次裡進行傳輸的TO(Data Transfer Object)都實現了Java.io.Serializable接口,看到這些偶突然感到茅塞頓開~困擾了很久的關於Serializable的疑問漸漸解開了,查找相關資料並總結如下:
序列化是什麼:
序列化就是將一個對象的狀態(各個屬性量)保存起來,然後在適當的時候再獲得。
序列化分為兩大部分:序列化和反序列化。序列化是這個過程的第一部分,將數據分解成字節流,以便存儲在文件中或在網絡上傳輸。反序列化就是打開字節流並重構對象。對象序列化不僅要將基本數據類型轉換成字節表示,有時還要恢復數據。恢復數據要求有恢復數據的對象實例
序列化的什麼特點:
如果某個類能夠被序列化,其子類也可以被序列化。聲明為static和transient類型的成員數據不能被序列化。因為static代表類的狀態, transIEnt代表對象的臨時數據。
什麼時候使用序列化:
一:對象序列化可以實現分布式對象。主要應用例如:RMI要利用對象序列化運行遠程主機上的服務,就像在本地機上運行對象時一樣。
二:Java對象序列化不僅保留一個對象的數據,而且遞歸保存對象引用的每個對象的數據。可以將整個對象層次寫入字節流中,可以保存在文件中或在網絡連接上傳遞。利用對象序列化可以進行對象的"深復制",即復制對象本身及引用的對象本身。序列化一個對象可能得到整個對象序列。
======================
可以看看接口Java.io.serializable的中文解釋:
Serializable
public interface Serializable
類通過實現 Java.io.Serializable 接口以啟用其序列化功能。未實現此接口的類將無法使其任何狀態序列化或反序列化。可序列化類的所有子類型本身都是可序列化的。序列化接口沒有方法或字段,僅用於標識可序列化的語義。
要允許不可序列化類的子類型序列化,可以假定該子類型負責保存和還原超類型的公用 (public)、受保護的 (protected) 和(如果可訪問)包 (package) 字段的狀態。僅在子類型擴展的類有一個可訪問的無參數構造方法來初始化該類的狀態時,才可以假定子類型有此責任。如果不是這種情況,則聲明一個類為可序列化類是錯誤的。該錯誤將在運行時檢測到。
在反序列化過程中,將使用該類的公用或受保護的無參數構造方法初始化不可序列化類的字段。可序列化的子類必須能夠訪問無參數的構造方法。可序列化子類的字段將從該流中還原。
當遍歷一個圖形時,可能會遇到不支持可序列化接口的對象。在此情況下,將拋出 NotSerializableException,並將標識不可序列化對象的類。
在序列化和反序列化過程中需要特殊處理的類必須使用下列准確簽名來實現特殊方法:
private void writeObject(Java.io.ObjectOutputStream out)
throws IOException
private void readObject(Java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
writeObject 方法負責寫入特定類的對象的狀態,以便相應的 readObject 方法可以還原它。通過調用 out.defaultWriteObject 可以調用保存 Object 的字段的默認機制。該方法本身不需要涉及屬於其超類或子類的狀態。狀態是通過使用 writeObject 方法或使用 DataOutput 支持的用於基本數據類型的方法將各個字段寫入 ObjectOutputStream 來保存的。
readObject 方法負責從流中讀取並還原類字段。它可以調用 in.defaultReadObject 來調用默認機制,以還原對象的非靜態和非瞬態字段。defaultReadObject 方法使用流中的信息來分配流中通過當前對象中相應命名字段保存的對象的字段。這用於處理類發展後需要添加新字段的情形。該方法本身不需要涉及屬於其超類或子類的狀態。狀態是通過使用 writeObject 方法或使用 DataOutput 支持的用於基本數據類型的方法將各個字段寫入 ObjectOutputStream 來保存的。
將對象寫入流時需要指定要使用的替代對象的可序列化類,應使用准確的簽名來實現此特殊方法:
ANY-Access-MODIFIER Object writeReplace() throws ObjectStreamException;
此 writeReplace 方法將由序列化調用,前提是如果此方法存在,而且它可以通過被序列化對象的類中定義的一個方法訪問。因此,該方法可以擁有私有 (private)、受保護的 (protected) 和包私有 (package-private) 訪問。子類對此方法的訪問遵循 Java 訪問規則。
在從流中讀取類的一個實例時需要指定替代的類應使用的准確簽名來實現此特殊方法。
ANY-Access-MODIFIER Object readResolve() throws ObjectStreamException;
此 readResolve 方法遵循與 writeReplace 相同的調用規則和訪問規則。
序列化運行時使用一個稱為 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 字段作為繼承成員沒有用處。
Java.io.Serializable引發的問題——什麼是序列化?在什麼情況下將類序列化?
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化。可以對流化後的對象進行讀寫操作,也可將流化後的對象傳輸於網絡之間。序列化是為了解決在對對象流進行讀寫操作時所引發的問題。序列化的實現:將需要被序列化的類實現Serializable接口,該接口沒有需要實現的方法,implements Serializable只是為了標注該對象是可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個 ObjectOutputStream(對象流)對象,接著,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數為obj的對象寫出(即保存其狀態),要恢復的話則用輸入流。
序列化:序列化是將對象轉換為容易傳輸的格式的過程。例如,可以序列化一個對象,然後使用 HTTP 通過 Internet 在客戶端和服務器之間傳輸該對象。在另一端,反序列化將從該流重新構造對象。
是對象永久化的一種機制。
確切的說應該是對象的序列化,一般程序在運行時,產生對象,這些對象隨著程序的停止運行而消失,但如果我們想把某些對象(因為是對象,所以有各自不同的特性)保存下來,在程序終止運行後,這些對象仍然存在,可以在程序再次運行時讀取這些對象的值,或者在其他程序中利用這些保存下來的對象。這種情況下就要用到對象的序列化。
只有序列化的對象才可以存儲在存儲設備上。為了對象的序列化而需要繼承的接口也只是一個象征性的接口而已,也就是說繼承這個接口說明這個對象可以被序列化了,沒有其他的目的。之所以需要對象序列化,是因為有時候對象需要在網絡上傳輸,傳輸的時候需要這種序列化處理,從服務器硬盤上把序列化的對象取出,然後通過網絡傳到客戶端,再由客戶端把序列化的對象讀入內存,執行相應的處理。
對象序列化是java的一個特征,通過該特征可以將對象寫作一組字節碼,當在其他位置讀到這些字節碼時,可以依此創建一個新的對象,而且新對象的狀態與原對象完全相同。為了實現對象序列化,要求必須能夠訪問類的私有變量,從而保證對象狀態能夠正確的得以保存和恢復。相應的,對象序列化API能夠在對象重建時,將這些值還原給私有的數據成員。這是對Java語言訪問權限的挑戰。通常用在服務器客戶端的對象交換上面,另外就是在本機的存儲。
對象序列化的最主要的用處就是在傳遞,和保存對象(object)的時候,保證對象的完整性和可傳遞性。譬如通過網絡傳輸,或者把一個對象保存成一個文件的時候,要實現序列化接口 。
*
Quote:
比較java.io.Externalizable和Java.io.Serializable
[URL]http://www.zdnet.com.cn/developer/code/story/0,3800066897,39304080,00.htm[/URL]
即使你沒有用過對象序列化(serialization),你可能也知道它。但你是否知道 Java 還支持另外一種形式的對象持久化,外部化(externalization)?
下面是序列化和外部化在代碼級的關聯方式:
public interface Serializable {}
public interface Externalizable extends Serializable {
void readExternal(ObjectInput in);
void writeExternal(ObjectOutput out);
}
序列化和外部化的主要區別
外部化和序列化是實現同一目標的兩種不同方法。下面讓我們分析一下序列化和外部化之間的主要區別。
通過Serializable接口對對象序列化的支持是內建於核心 API 的,但是java.io.Externalizable的所有實現者必須提供讀取和寫出的實現。Java 已經具有了對序列化的內建支持,也就是說只要制作自己的類java.io.Serializable,Java 就會試圖存儲和重組你的對象。如果使用外部化,你就可以選擇完全由自己完成讀取和寫出的工作,Java 對外部化所提供的唯一支持是接口:
voidreadExternal(ObjectInput in)
void writeExternal(ObjectOutput out)
現在如何實現readExternal() 和writeExternal() 就完全看你自己了。
序列化會自動存儲必要的信息,用以反序列化被存儲的實例,而外部化則只保存被存儲的類的標識。當你通過 java.io.Serializable接口序列化一個對象時,有關類的信息,比如它的屬性和這些屬性的類型,都與實例數據一起被存儲起來。在選擇走 Externalizable這條路時,Java 只存儲有關每個被存儲類型的非常少的信息。
每個接口的優點和缺點
Serializable接口
· 優點:內建支持
· 優點:易於實現
· 缺點:占用空間過大
· 缺點:由於額外的開銷導致速度變比較慢
Externalizable接口
· 優點:開銷較少(程序員決定存儲什麼)
· 優點:可能的速度提升
· 缺點:虛擬機不提供任何幫助,也就是說所有的工作都落到了開發人員的肩上。
在兩者之間如何選擇要根據應用程序的需求來定。Serializable通常是最簡單的解決方案,但是它可能會導致出現不可接受的性能問題或空間問題;在出現這些問題的情況下,Externalizable可能是一條可行之路。
要記住一點,如果一個類是可外部化的(Externalizable),那麼Externalizable方法將被用於序列化類的實例,即使這個類型提供了Serializable方法:
private void writeObject()
private void readObject()