Java自定义序列化行为解析
发布时间:2011-5-1 20:00
发布者:1046235000
正常情况下,一个类实现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 之后。 |
网友评论