Java自定义序列化行为解析

发布时间:2011-5-1 20:00    发布者:1046235000
关键词: java , 自定义序列化行为
正常情况下,一个类实现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
    之后。
本文地址:https://www.eechina.com/thread-64041-1-1.html     【打印本页】

本站部分文章为转载或网友发布,目的在于传递和分享信息,并不代表本网赞同其观点和对其真实性负责;文章版权归原作者及原出处所有,如涉及作品内容、版权和其它问题,我们将根据著作权人的要求,第一时间更正或删除。
您需要登录后才可以发表评论 登录 | 立即注册

厂商推荐

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
快速回复 返回顶部 返回列表