正常情況下,一個類實現java序列化很簡單,只需要implements Serializable接口即可,之后該類在跨jvm 的傳輸過程中會遵照默認java序列化規則序列化和反序列化;不同jvm 版本之間序列化方式稍有不同,但基本上都是兼容的。在某些特殊情況下,可能需要自定義序列化和反序列化的行為,看下面例子: Java代碼 class AbstractSerializeDemo { private int x , y; public void init(int x , int y) { this.x = x; this.y = y; } public int getX () { return x; } public int getY () { return y; } public void printXY () { System.out.println("x:" + x + " ;y :" + y ); } } public class SerializeDemo extends AbstractSerializeDemo implements Serializable { private int z ; public SerializeDemo() { super.init(10, 50 ); z = 100 ; } public void printZ() { super.printXY (); System.out.println("z:" + z ); } public static void main (String[] args ) throws IOException , ClassNotFoundException { ByteArrayOutputStream bos = new ByteArrayOutputStream (); ObjectOutputStream out = new ObjectOutputStream (bos ); SerializeDemo sd = new SerializeDemo(); sd.printZ (); out.writeObject (sd); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream (bos.toByteArray ())); SerializeDemo sd2 = (SerializeDemo ) in.readObject(); sd2.printZ(); } } 這段程序表示了一個可序列化的類繼承自一個非序列化的有狀態超類,期望的結果是,子類序列化以后傳輸并反序列化回來,原先的值域包括超類的值域都保持不變。 但是輸出是: Java代碼 x :10;y :50 z :100 x :0 ;y :0 z :100 結果和期望不符,子類的值域保留下來了,但是超類的值域丟失了,這對jvm 來說是正常的,因為超類不可序列化;為了解決這個問題,只能自定義序列化行為,具體做法是在SerializeDemo里加入以下代碼: Java代碼 private void writeObject(ObjectOutputStream os ) throws IOException { os.defaultWriteObject ();//java對象序列化默認操作 os.writeInt (getX()); os.writeInt (getY()); } private void readObject (ObjectInputStream is) throws IOException ,ClassNotFoundException { is.defaultReadObject();//java對象反序列化默認操作 int x=is.readInt(); int y=is.readInt(); super.init(x ,y ); } writeObject 和readObject方法為JVM 會在序列化和反序列化java對象時 會分別調用的兩個方法,修飾符都是private ,沒錯。我們在序列化的默認動作之后將超類里的兩個值域x 和y 也寫入object流;與之對應在反序列化的默認操作之后讀入x 和y 兩個值,然后調用超類的初始化方法。 再次執行程序之后的輸出為: Java代碼 x :10;y :50 z :100 x :10;y :50 z :100 另外還有兩個自定義序列化方法writeReplace和readResolve ,分別用來在序列化之前替換序列化對象和在反序列化之后的對返回對象的處理。一般可以用來避免singleTon 對象跨jvm 序列化和反序列化時產生多個對象實例,事實上singleTon 的對象一旦可序列化,它就不能保證singleTon 了。JVM 的Enum實現里就是重寫了readResolve 方法,由JVM 保證Enum的值都是singleTon 的,所以建議多使用Enum代替使用writeReplace和readResolve 方法。 Java代碼 private Object readResolve() { return INSTANCE ; } private Object writeReplace (){ return INSTANCE ; } 注:writeReplace調用在writeObject 前;readResolve 調用在readObject 之后。 |