正常情況下,一個類實作java序列化很簡單,隻需要implements Serializable接口即可,之後該類在跨jvm的傳輸過程中會遵照預設java序列化規則序列化和反序列化;不同jvm版本之間序列化方式稍有不同,但基本上都是相容的。
在某些特殊情況下,可能需要自定義序列化和反序列化的行為,看下面例子:
Java代碼
classAbstractSerializeDemo {
privateintx, y;
publicvoidinit(intx,inty) {
this.x = x;
this.y = y;
}
publicintgetX() {
returnx;
}
publicintgetY() {
returny;
}
publicvoidprintXY() {
System.out.println("x:"+ x +";y:"+ y);
}
}
publicclassSerializeDemoextendsAbstractSerializeDemoimplementsSerializable {
privateintz;
publicSerializeDemo() {
super.init(10,50);
z =100;
}
publicvoidprintZ() {
super.printXY();
System.out.println("z:"+ z);
}
publicstaticvoidmain(String[] args)throwsIOException, ClassNotFoundException {
ByteArrayOutputStream bos =newByteArrayOutputStream();
ObjectOutputStream out =newObjectOutputStream(bos);
SerializeDemo sd =newSerializeDemo();
sd.printZ();
out.writeObject(sd);
ObjectInputStream in =newObjectInputStream(newByteArrayInputStream(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代碼
privatevoidwriteObject(ObjectOutputStream os)throwsIOException {
os.defaultWriteObject();//java對象序列化預設操作
os.writeInt(getX());
os.writeInt(getY());
}
privatevoidreadObject(ObjectInputStream is)throwsIOException, ClassNotFoundException {
is.defaultReadObject();//java對象反序列化預設操作
intx=is.readInt();
inty=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代碼
privateObject readResolve()
{
returnINSTANCE;
}
privateObject writeReplace(){
returnINSTANCE;
}
注:writeReplace調用在writeObject前;readResolve調用在readObject之後。
【編輯推薦】
【責任編輯:金賀 TEL:(010)68476606】
點贊 0