Java自定義序列化行為解析
正常情況下,一個(gè)類實(shí)現(xiàn)java序列化很簡單,只需要implements Serializable接口即可,之后該類在跨jvm的傳輸過程中會(huì)遵照默認(rèn)java序列化規(guī)則序列化和反序列化;不同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();
 - }
 - }
 
這段程序表示了一個(gè)可序列化的類繼承自一個(gè)非序列化的有狀態(tài)超類,期望的結(jié)果是,子類序列化以后傳輸并反序列化回來,原先的值域包括超類的值域都保持不變。
但是輸出是:
Java代碼
- x:10;y:50
 - z:100
 - x:0;y:0
 - z:100
 
結(jié)果和期望不符,子類的值域保留下來了,但是超類的值域丟失了,這對jvm來說是正常的,因?yàn)槌惒豢尚蛄谢?
為了解決這個(gè)問題,只能自定義序列化行為,具體做法是在SerializeDemo里加入以下代碼:
Java代碼
- private void writeObject(ObjectOutputStream os) throws IOException {
 - os.defaultWriteObject();//java對象序列化默認(rèn)操作
 - os.writeInt(getX());
 - os.writeInt(getY());
 - }
 - private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
 - is.defaultReadObject();//java對象反序列化默認(rèn)操作
 - int x=is.readInt();
 - int y=is.readInt();
 - super.init(x,y);
 - }
 
writeObject和readObject方法為JVM會(huì)在序列化和反序列化java對象時(shí)會(huì)分別調(diào)用的兩個(gè)方法,修飾符都是private,沒錯(cuò)。
我們在序列化的默認(rèn)動(dòng)作之后將超類里的兩個(gè)值域x和y也寫入object流;與之對應(yīng)在反序列化的默認(rèn)操作之后讀入x和y兩個(gè)值,然后調(diào)用超類的初始化方法。
再次執(zhí)行程序之后的輸出為:
Java代碼
- x:10;y:50
 - z:100
 - x:10;y:50
 - z:100
 
另外還有兩個(gè)自定義序列化方法writeReplace和readResolve,分別用來在序列化之前替換序列化對象 和 在反序列化之后的對返回對象的處理。一般可以用來避免singleTon對象跨jvm序列化和反序列化時(shí)產(chǎn)生多個(gè)對象實(shí)例,事實(shí)上singleTon的對象一旦可序列化,它就不能保證singleTon了。JVM的Enum實(shí)現(xiàn)里就是重寫了readResolve方法,由JVM保證Enum的值都是singleTon的,所以建議多使用Enum代替使用writeReplace和readResolve方法。
Java代碼
- private Object readResolve()
 - {
 - return INSTANCE;
 - }
 - private Object writeReplace(){
 - return INSTANCE;
 - }
 
注:writeReplace調(diào)用在writeObject前;readResolve調(diào)用在readObject之后。
【編輯推薦】















 
 
 




 
 
 
 