纯粹是个人学习总结,如有不对的地方请吐槽。
“对象序列化”(Object Serialization)是 Java1.1就开始有的特性。 简单地说,就是可以将一个对象(标志对象的类型)及其状态转换为字节码,保存起来(可以保存在数据库,内存,文件等),然后可以在适当的时候再将其状态恢复(也就是反序列化)。serialization 不但可以在本机做,而且可以经由网络操作。它自动屏蔽了操作系统的差异,字节顺序等。比如,在 Windows 平台生成一个对象并序列化之,然后通过网络传到一台 Unix 机器上,然后可以在这台Unix机器上正确地重构(deserialization)这个对象。 不必关心数据在不同机器上如何表示,也不必关心字节的顺序或者其他任何细节。
java.io.Serializable接口没有任何方法属性域,实现它的类只是从语义上表明自己是可以序列化的。
在对一个 Serializable(可序列化)对象进行重新装配的过程中,不会调用任何构建器(甚至默认构建器)。整个对象都是通过从 InputStream 中取得数据恢复的。
如是要一个类是可序列化的,那么它的子类也是可序列化的。
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式。
特殊情况-父类不可序列化而子类可序列化
我们看到,对于B的属性b1,其可以正确的序列化,但对于其从A继承过来的属性a,b则没有正确的序列化。为什么呢?我们再看上面的运行结果,可以发现:反序列化的时候,由于B实现了Serializable,所在以反序列化的时候,它并不会调用它自己的构造器,但是,在反序列化B的时候,却调用了它的超类的构造器(实际上不仅仅是构造器,A的所有的初始化过程都会正常进行)。这正是上面结果中a,b的值没有正确反序列化的原因。
于是,对于这种父类非序列化而子类可序列化的类,子类应该自己对超类的public,protected,以及 friedly 属性进行单独处理。
方法是不带状态的,就是一些指令,指令是不需要序列化的,只要你的JVM classloader可以load到这个类,那么类方法指令自然就可以获得。序列化真正需要保存的只是对象属性的值,和对象的类型。
请记住序列化机制只保存对象的类型信息,属性的类型信息和属性值,和方法没有什么关系,你就是给这个类增加10000个方法,序列化内容也不会增加任何东西,不要想当然的臆测自己不了解的知识,动手去做!
序列化在 Effective Java 中讲得很清楚啊, 一般认为只声明实现 implements 接口, 不提供自定义的序列化形式是不负责任的做法, 这样可能导致比较多的问题比如类的不同版本之间的兼容性, 看看 Effective Java 中的条目吧
谨慎地实现 Serialiable
为了继承而设计的类应该很少实现 Serialiable, 接口也应该很少会扩展它. 如果违反了这条规则, 则扩展这个类或者实现这个接口的程序员会背上沉重的负担.
若没有认真考虑默认序列化形式是否合适, 则不要接受这种形式
即使你确定了默认序列化形式是合适的, 通常你仍然要提供一个 readObject方法以保证约束关系和约束性
不管你选择了哪种序列化形式, 你都要为自己编写的每个可序列化的类声明一个显式的序列版本 UID (serialVersionUID)