歡迎您光臨本站 註冊首頁

Java自定義序列化行為解析

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

正常情況下,一個類實現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
之後.


[火星人 ] Java自定義序列化行為解析已經有315次圍觀

http://coctec.com/docs/java/show-post-60028.html