??? 序列化是將對象變為連續的字節流,用于對象的持久化,網絡傳輸等場合
一個類希望能被序列化必須實現 Serializable 接口,Serializable 本身并沒有聲明任何
方法,只是起標記作用??尚蛄谢惖淖宇愖匀灰彩强尚蛄谢?。因而實現序列化是非常方
便的,只要在類的聲明時添加 implenment Serializable 就可以了,java 虛擬機會幫你處
理剩下的工作。序列化是遞歸的,一個類想要序列化則它的所有數據成員都必須是可以序列
化的,否則在序列化時會拋出 NotSerializableException 異常。jsdk 中基本數據類型的
封裝類(Integer, Float etc),Component 都是可序列化的,如果容器中的對象都是可
序列化的,則容器時可序列化的。java.lang.refect 包中的類不能序列化,Socket,
URLConnection 不能序列化。
對于只實現了 Serializable 接口的類,可以想象 java 是如何將它們序列化的:首先要利
用反射機制得到所有需要序列化的數據成員,包括 private 成員,得到 private 成員的過
程是非常規的,必定要經過嚴格的權限和安全檢查。所以用 java 自己的序列化方式開銷是
非常大的,這也是為什么會有這篇文章的原因,這里要討論 java 提供的可以由我們自己控
制的序列化對象的方式。
覆寫
private void writeObject(ObjectOutputStream out)
private void readObject(ObjectInputStream in)
這兩個方法會在對象序列化和反序列化時被調用,通過覆寫這兩個方法我們可以完全控制整
個序列化的過程。我們注意到這兩個方法都是 private ,這意味我們無法顯示的調用這兩
個方法,而 java 虛擬機在調用這兩個方法時也必然要經過嚴格的權限和安全檢查。與傳統
的序列化方式(只實現 Serializable 接口)相比,這種方法減少了利用反射的次數以及獲
取 private 成員所需要的額外開銷,因為在這兩個方法中所有的數據成員都是可以自由使
用的
實現 Externalizable 接口
該接口中定義了兩個方法
public void readExternal(ObjectInput in) throws IOException
public void writeExternal(ObjectOutput out)
?????? throws IOException, ClassNotFoundException
這兩個方法會在對象序列化和反序列化時被調用。很明顯這兩個方法都是 public 的,所以
我們可以顯示的將一個對象序列化到一個輸出流,而 java 虛擬機在調用這兩個方法時也不
會有任何的限制。
ANY-ACCESS_MODIFIER Object writeReplace() throws ObjectStreamException;
ANY-ACCESS_MODIFIER Object readResolve() throws ObjectStreamException;
這兩個方法在序列化和反序列化時被調用,可以替換將要寫入或讀出的對象,在實現Singleton模式
時可能會用到
這三種方法實現序列化效率是顯而易見的:傳統方式最慢,實現 Externalizable 接口方式
最快。但自己控制序列化過程有個明顯的缺點就是當類的數據成員改變時,序列化過程也同
時需要修改,相反這正好是傳統方式的優點:任何改動都不會影響對象的正確序列化,虛擬
機會幫你完成一切工作,雖然不算出色。
當我們考慮性能問題時,序列化總應該是我們首先要注意的方面,尤其是那些只實現了
Serializable 接口的類,它們往往就是性能的瓶頸所在,特別是一些對象需要反復的被序
列化和反序列化,實現 Externalizable 接口會給你不小的驚喜。而對于實現
Externalizable 接口后需要保持數據成員和序列化方法一致的問題實際算不上問題,因為
當我們考慮性能問題時應該已經到了編碼的最后階段,這時整體框架和數據結構都已經非常
穩定了,數據成員被修改的可能已經非常低了,即使被修改了,能大幅提高性能,多寫兩行代
碼也不是令人沮喪的事情。
以上只是單純的討論序列化的過程,實際上序列化總是和 I/O 操作同時發生,因為序列化
就是為了傳輸或是存儲,所以對 I/O 的優化方法在這里也是同樣適用的。
使用ObjectOutputStream.writeObject()時,在流的內部會有一個引用緩存,所有已經寫入流的
對象如果再次被寫入則直接使用以前引用而不重新傳輸新的對象,這樣可以提到流的效率,但同樣帶來
問題,一個對象寫入流后,被修改,再次寫入流,再另一端ObjectInputStream得到的是
兩個相同的對象,這一點一定要注意
posted on 2005-09-09 14:07
JBahamut 閱讀(635)
評論(3) 編輯 收藏