详解Java序列化和反序列化中各钩子方法的执行顺序

分类: Java

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

前面,我们通过两篇文章介绍了Java序列化和反序列化中的writeExternal、readExternal和writeReplace、readResolve四个方法。

那这四个方法具体的执行顺序如何呢?

我们直接通过一个示例进行演示。在示例中,我们在UserModel05中同时定义了以上四种方法,如下所示。

public class UserModel05 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);
        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 Object writeReplace() throws ObjectStreamException {
        System.out.println("writeReplace doing ...");
        UserModel05 userModel = new UserModel05();
        userModel.setId(2);
        userModel.setName(name + "(from writeReplace)");
        userModel.setDescription("description from writeReplace");
        return userModel;
    }

    private Object readResolve() throws ObjectStreamException {
        System.out.println("readResolve doing ...");
        UserModel05 userModel = new UserModel05();
        userModel.setId(2);
        userModel.setName(name + "(from readResolve)");
        userModel.setDescription("description from readResolve");
        return userModel;
    }
}

然后我们对UserModel05的对象进行序列化和反序列化,如下所示。

private static void demo05() throws Exception {
    System.out.println("run demo05:");
    UserModel05 userModel05 = new UserModel05();
    userModel05.setId(1);
    userModel05.setName("易哥");

    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("m5.tempdata"));
    oos.writeObject(userModel05);
    oos.flush();
    oos.close();

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

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("m5.tempdata"));
    UserModel05 newUser = (UserModel05) ois.readObject();
    System.out.println("newUser:" + newUser.getId() + "-" + newUser.getName());
    System.out.println("description:" + newUser.getDescription());
    System.out.println();
}

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

程序运行结果

图中展示的UserModel05对象的name属性中便记录了所有方法的执行顺序。四个方法的执行顺序依次为:writeReplace、writeExternal、readExternal、readResolve。我们可以用下图将继承Externalizable接口的类的序列化和反序列化流程展示出来:

Externalizable接口实现类中方法的执行顺序

继承Serializable接口的类的序列化和反序列化流程相对简单一些,如下所示。

Serializable接口实现类中方法的执行顺序

至此为止,我们已经介绍完成了Java序列化和反序列化过程中的所有钩子方法,并理清楚了他们的执行顺序关系。以上内容均参考《通用源码阅读指导书——MyBatis源码详解》一书。

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

《通用源码阅读指导书》

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

书中的“22.3.3 懒加载功能对序列化和反序列化的支持”章节介绍了懒加载中的序列化和反序列化操作,大家可以前往阅读,来详细了解MyBatis如何用它来完成目标对象的序列化与反序列化操作。

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

作者书籍推荐

作者书籍推荐 作者书籍推荐