序列化相关文章:
阅读本文章之前,务必要阅读上面的三篇文章。
这篇文章是围绕上面三篇文章的原理进行剖析的。
因为 ObjectInputStream 和 ObjectOutputStream 类比较复杂,这里只解析跟上面三篇文章相关的内容。
java 序列化示例
public class Test{
public static void main(String[] args) throws Exception {
File file = new File("d:\\a.user");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(User.getInstance());
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
User user = (User) ois.readObject();
ois.close();
System.out.println(user);
if(user==User.getInstance()){
System.out.println("同一个实例");
}else{
System.out.println("不同的实例");
}
}
}
通过该示例,我们知道 Java 序列化是由 ObjectInputStream 和 ObjectOutputStream 两个类实现的,下面我们就通过这两个类来揭开 Java 序列化的神秘面纱。
ObjectOutputStream 原理解析
writeObject 方法
1、通过 enableOverride 判断是否执行 writeObjectOverride() 方法。
2、调用writeObject() 方法。
writeObjectOverride() 方法
通过源码发现这个方法是个空方法,这是搞什么鬼?
仔细分析后可以发现 writeObject 方法是final 类型的,也就是子类无法重写的,通过 向子类暴露 writeObjectOverride 方法来达到重写的目的。
writeObject0方法
在 writeObject0() 方法中,跳过一些检查操作,直接分析最核心的这段代码。
1、 如果该对象是String、数组、枚举类型的,调用响应的方法进行写入。
在这里String和 Enum 类型不实现 Serializable 也可以序列化的,但String 类中还是实现了 Serializable 接口,告诉大家,该类可以序列化的。
2、如果对象是 Serializable 的,则调用 writeOrdinaryObject() 方法,该方法是序列化的核心方法。
在这里我们终于看到 Serializable的作用了。因为Serializable中没有定义方法,只是起到标识作用,该标识作用就在这提现。
writeOrdinaryObject 方法
1、检查是否可以序列化
2、写入类型
3、写 class 的描述信息
4、判断是 该对象 否实现了 Externalizable 接口
- 如果实现了则调用 writeExternalData 方法。
- 如果没有实现则调用 writeSerialData 方法。
这里,我们可以看到,如果实现了 Externalizable 接口,会优先执行 Externalizable 接口的实现的方法,而默认的序列化方法不会执行。
这里也解释了上一篇文章中Java 序列化之 Externalizable 示例三 的原因。
writeExternalData 方法
实现 Externalizable 序列化接口
通过该方法可以看到,在这里会调用我们自己定义的 WriteExternal() 方法。
writeSerialData 方法
实现 Serializable 序列化接口
- 1、判断该类是否定义了 writeObject() 方法,如果定义了,则通过反射调用该对象的 writeObject() 方法,执行我们自己定义的序列化规则。
- 2、没有定义writeObject() 方法,则调用 defaultWriteFields() 方法执行默认的序列化规则。
我们平常在重写 writeObject() 方法的时候一般也会先调用 defaultWriteFields() 方法的,然后在写上其它特殊的序列化。
ObjectInputStream 原理解析
ObjectInputStream 原理其实同 ObjectOutputStream 差不多,明白 ObjectInputStream 后再看 ObjectoutputStream 就很 easy 了。
readObject 方法
1、提供给子类进行重写反序列化功能(readObject 方法是final的,但提供 readObjectOverride() 给子类去覆盖实现)
2、反序列化调用 readObject0() 方法去实现。
readObject0 方法
该方法中提供了好多类型的反序列化方法支持。
但是我们这里只关注 Object类型的反序列化。这里调用的是 readOrdinaryObject() 。
readOrdinaryObject 方法
1、判断该类是否实现了 Externalizable 接口,如果实现了Externalizable 接口,就执行readExternalData () 方法
2、否则,执行 readSerialData() 方法,使用默认的 Serializable 接口的反序列化方法执行发序列化。
3、判断该类是否定义了 readResolve() 方法,如果定义了 readResolveMethod() 方法,则执行用户定义的 readResolve() 方法。该方法的作用,请参考文章: Java 序列化 之 单例模式。
readExternalData 方法
调用用户实现的 readExternal() 方法实现对象的反序列化。
readSerialData 方法
判断用户是否实现了 readObject() 方法,如果实现,则执行用户自定义的发序列化方法。
否则执行ObjectInputStream中默认的序列化方法 defaultReadFields();
通过ObjectOutputStream 类的简单分析,我们就可以了解到 Serializable 和 Externalizable 的原理。
想了解更多精彩内容请关注我的公众号
网友评论