Java序列化与反序列化
问题
在Cluster环境下配置Quartz job和EhCache时,Quartz job类及相关属性都要实现java.io.Serializable接口,EhCache管理的Cache内容需要在各个节点间同步,所以EhCache管理的Cache类也要实现Serializable接口。我对Serializable接口的认知停留在如下方面:
1. 实现Serializable接口只是个标记,不需要做额外的操作。
2. 如果父类实现了Serializable接口,所有子类都是可序列化的。
3. 序列化只是存储对象的状态。
这三个认识是正确的,但在测试Cluster时,发现一些与序列化和反序列化相关的更深层次的问题。
试验
我写了几个类来简化我的问题描述和验证我的想法。测试代码里包含五个类(参见下图),其中2个是测试类。Child类是Parent的子类,Child对象声明了一个类型为ThirdObject的属性thirdObject。如下场景都基于Child实现了Serializable接口这个假设。
1. 考虑单个类的和ThirdObject没有实现Serializable接口的情况:
a. Child的属性thirdObject为null时,序列化Child类的实例不会报错。
b. Child的属性thirdObject为非空时,序列化Child类的实例会报错。反序列化Child时,也能正确读取thirdObject的值。
c. Child的属性thirdObject加Static修饰符时,序列化Child类的实例不会报错,反序列化Child时,不能正确取出thirdObject的值。
2. 考虑父子类,thirdObject作为Parent的一个属性而不是Child的一个属性的情况。
a. 当Parent类实现序列化接口时,如果ThirdObject没有实现Serializable接口,与第一种情况类似。
b. 当Parent类实现序列化接口时,如果ThirdObject类实现了Serializable接口, 序列化Child类的实例不会报错,反序列化Child时,Parent类的thirdObject属性值也能正确读取。
c. 当Parent类没有实现序列化接口时,序列化Child类的实例不会报错,但反序列化Child时,Parent的thirdObject属性值为空。
结论
通过上述的测试结果和网上资料的Check,总结如下:
1. 默认序列化不会序列化静态变量。
2. 默认序列化不会序列化transient的实例变量。
3. 在反序列化时不会调用类的任何构造方法。但会执行静态代码块和静态变量的初始化。因为这个在Class Load的过程中会执行。
4. 当父类没有实现Serializable接口时,序列化子类虽然不会报错,但是父类实际上没有被序列化,如果需要序列化父类的属性,子类需要写相应的逻辑。