详解Java序列化和反序列化中的writeExternal方法和readExternal方法

标签: Java

保留所有版权,请引用而不是转载本文(原文地址 https://yeecode.top/blog/64/ )。

要表明一个类的对象是可序列化的则必须要继承Serializable接口或者Externalizable接口,而且Externalizable接口是Serializable接口的子接口。这些内容我们在前面的文章中均已经介绍过,还给出了继承Serializable接口进行序列化和反序列化的示例。

继承Serializable接口实现序列化和反序列化是非常简单的,目标类除了继承Serializable接口外不需要任何其他的操作,整个序列化和反序列化的过程由Java内部的机制完成。而继承Externalizable接口实现序列化和反序列化则支持自定义序列化和反序列化的方法。Externalizable接口包含两个抽象方法:

我们通过示例来说明writeExternal方法和readExternal方法的作用。在下面代码中,我们设置了UserModel02类的writeExternal方法和readExternal方法。

public class UserModel02 implements Externalizable {
    private static final long serialVerisionUID = 1L;

    private Integer id;
    private String name;
    private String description;

    // 省略属性的get、set方法

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("writeExternal doing ...");
        out.write(id); // DataOutput中的方法
        out.writeObject(name + "(from writeExternal)");
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        System.out.println("readExternal doing ...");
        id = in.read();
        name = (String) in.readObject();
        System.out.println("name in file is:" + name);
        name = name + "(from readExternal)";
    }
}

然后我们对上述类的实例进行序列化和反序列化,过程如下所示。

private static void demo02() throws Exception {
    System.out.println("run demo02:");
    UserModel02 userModel02 = new UserModel02();
    userModel02.setId(1);
    userModel02.setName("易哥");

    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("m2.tempdata"));
    oos.writeObject(userModel02);
    oos.flush();
    oos.close();

    System.out.println("↑write;↓read");

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("m2.tempdata"));
    UserModel02 newUser = (UserModel02) ois.readObject();
    System.out.println("newUser:" + newUser.getId() + "-" + newUser.getName());
    System.out.println();
}

最终的到了下图所示的运行结果。

图 22-3 程序运行结果

可见,对于实现了Externalizable接口的类,会在对象的序列化时调用writeExternal方法,而在对象的反序列化时调用readExternal方法。

因为我们可以通过自定义writeExternal方法和readExternal方法的具体实现,来控制对象的序列化和反序列化行为。这也使得继承Externalizable接口实现序列化和反序列化更为自由和强大。

以上内容均参考《通用源码阅读指导书——MyBatis源码详解》一书。

通用源码阅读指导书-京东自营

《通用源码阅读指导书》

这是一本以MyBatis的源码为实例讲述源码阅读方法的书籍,并且附带有示例项目源码,MyBatis的全中文注解。书籍还总结了大量的编程知识和架构经验,对提升编程和架构能力十分有用。

书中的“22.3.3 懒加载功能对序列化和反序列化的支持”章节介绍了懒加载中的序列化和反序列化操作,大家可以前往阅读。

在接下来的文章中,我们会介绍序列化和反序列化中的writeReplace方法和readResolve方法,还会进一步介绍序列化和反序列化过程中各个方法的执行顺序。

可以访问个人知乎阅读更多文章:易哥(https://www.zhihu.com/people/yeecode),欢迎关注。

作者书籍推荐