java 序列化 原理解析
序列化相关文章:
阅读本文章之前,务必要阅读上面的三篇文章。
这篇文章是围绕上面三篇文章的原理进行剖析的。
因为 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 方法
![](https://img.haomeiwen.com/i2843224/5452eebcc602605a.png)
1、通过 enableOverride 判断是否执行 writeObjectOverride() 方法。
2、调用writeObject() 方法。
writeObjectOverride() 方法
![](https://img.haomeiwen.com/i2843224/7ecd1f33877ebc37.png)
通过源码发现这个方法是个空方法,这是搞什么鬼?
仔细分析后可以发现 writeObject 方法是final 类型的,也就是子类无法重写的,通过 向子类暴露 writeObjectOverride 方法来达到重写的目的。
writeObject0方法
![](https://img.haomeiwen.com/i2843224/404962aae4a19276.png)
在 writeObject0() 方法中,跳过一些检查操作,直接分析最核心的这段代码。
1、 如果该对象是String、数组、枚举类型的,调用响应的方法进行写入。
在这里String和 Enum 类型不实现 Serializable 也可以序列化的,但String 类中还是实现了 Serializable 接口,告诉大家,该类可以序列化的。
2、如果对象是 Serializable 的,则调用 writeOrdinaryObject() 方法,该方法是序列化的核心方法。
在这里我们终于看到 Serializable的作用了。因为Serializable中没有定义方法,只是起到标识作用,该标识作用就在这提现。
writeOrdinaryObject 方法
![](https://img.haomeiwen.com/i2843224/a43fad14bf3a0340.png)
1、检查是否可以序列化
2、写入类型
3、写 class 的描述信息
4、判断是 该对象 否实现了 Externalizable 接口
- 如果实现了则调用 writeExternalData 方法。
- 如果没有实现则调用 writeSerialData 方法。
这里,我们可以看到,如果实现了 Externalizable 接口,会优先执行 Externalizable 接口的实现的方法,而默认的序列化方法不会执行。
这里也解释了上一篇文章中Java 序列化之 Externalizable 示例三 的原因。
writeExternalData 方法
实现 Externalizable 序列化接口
![](https://img.haomeiwen.com/i2843224/d2084ed500472815.png)
通过该方法可以看到,在这里会调用我们自己定义的 WriteExternal() 方法。
writeSerialData 方法
实现 Serializable 序列化接口
![](https://img.haomeiwen.com/i2843224/c5c858946e16e8db.png)
- 1、判断该类是否定义了 writeObject() 方法,如果定义了,则通过反射调用该对象的 writeObject() 方法,执行我们自己定义的序列化规则。
- 2、没有定义writeObject() 方法,则调用 defaultWriteFields() 方法执行默认的序列化规则。
我们平常在重写 writeObject() 方法的时候一般也会先调用 defaultWriteFields() 方法的,然后在写上其它特殊的序列化。
ObjectInputStream 原理解析
ObjectInputStream 原理其实同 ObjectOutputStream 差不多,明白 ObjectInputStream 后再看 ObjectoutputStream 就很 easy 了。
readObject 方法
![](https://img.haomeiwen.com/i2843224/d9b10893567927ba.png)
1、提供给子类进行重写反序列化功能(readObject 方法是final的,但提供 readObjectOverride() 给子类去覆盖实现)
2、反序列化调用 readObject0() 方法去实现。
readObject0 方法
![](https://img.haomeiwen.com/i2843224/fc913021364f647f.png)
该方法中提供了好多类型的反序列化方法支持。
但是我们这里只关注 Object类型的反序列化。这里调用的是 readOrdinaryObject() 。
readOrdinaryObject 方法
![](https://img.haomeiwen.com/i2843224/2a10d9c4647ca55a.png)
1、判断该类是否实现了 Externalizable 接口,如果实现了Externalizable 接口,就执行readExternalData () 方法
2、否则,执行 readSerialData() 方法,使用默认的 Serializable 接口的反序列化方法执行发序列化。
3、判断该类是否定义了 readResolve() 方法,如果定义了 readResolveMethod() 方法,则执行用户定义的 readResolve() 方法。该方法的作用,请参考文章: Java 序列化 之 单例模式。
readExternalData 方法
![](https://img.haomeiwen.com/i2843224/ab9f14dee4d89502.png)
调用用户实现的 readExternal() 方法实现对象的反序列化。
readSerialData 方法
![](https://img.haomeiwen.com/i2843224/d2fb36bbb4af7d98.png)
判断用户是否实现了 readObject() 方法,如果实现,则执行用户自定义的发序列化方法。
![](https://img.haomeiwen.com/i2843224/83187a4853e3300a.png)
否则执行ObjectInputStream中默认的序列化方法 defaultReadFields();
通过ObjectOutputStream 类的简单分析,我们就可以了解到 Serializable 和 Externalizable 的原理。
想了解更多精彩内容请关注我的公众号
![](https://img.haomeiwen.com/i2843224/af50fe51e979ebd0.png)