详解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接口的类的序列化和反序列化流程展示出来:
继承Serializable接口的类的序列化和反序列化流程相对简单一些,如下所示。
至此为止,我们已经介绍完成了Java序列化和反序列化过程中的所有钩子方法,并理清楚了他们的执行顺序关系。以上内容均参考《通用源码阅读指导书——MyBatis源码详解》一书。
这是一本以MyBatis的源码为实例讲述源码阅读方法的书籍,并且附带有示例项目源码,MyBatis的全中文注解。书籍还总结了大量的编程知识和架构经验,对提升编程和架构能力十分有用。
书中的“22.3.3 懒加载功能对序列化和反序列化的支持”章节介绍了懒加载中的序列化和反序列化操作,大家可以前往阅读,来详细了解MyBatis如何用它来完成目标对象的序列化与反序列化操作。
可以访问个人知乎阅读更多文章:易哥(https://www.zhihu.com/people/yeecode),欢迎关注。
