因为之前面试中被问到过序列化的问题,所以今天就来整理一下关于对象序列化的知识点。
(1) 什么是将该对象序列化?
概念:对象序列化就是将对象编码成字节流,并从字节流编码中重新构建对象。“将一个对象编码成一个字节流”,称作将该对象序列化。相反的过程称作反序列化。
(2)序列化有什么作用?
作用:==一旦对象被序列化之后,其编码就可以从一台正在运行的虚拟机被传递到另一台虚拟机上,或者被存储到磁盘上,供以后反序列化时用。==序列化技术为远程通信提供了标准的线路级表示法,也为javaBeans组件结构提供了标准的持久化数据格式。
(3)如何实现对象序列化?
方法:要想使一个类的实例可被序列化,只要在其声明中加入“implements Serializable”即实现序列化接口即可。
看似实现序列化是十分容易的,但是实际上为了实现序列化而付出的开销往往是实实在在的。
(4)实现序列化接口付出了什么代价?
- 代价一:实现Serializable接口而付出的最大代价是:一旦一个类被发布,就大大降低了“改变这个类的实现”的灵活性。
如果一个类实现了Serializable接口,它的字节流编码(也称序列化形式)就变成了它的导出的API的一部分,一旦这个类被广泛使用,往往必须永远支持这种序列化形式。如果不是自定义的序列化形式,而选择的是默认的序列化形式,那么这个类中私有的和包级私有的实例域都将变成导出API的一部分,就失去了作为信息隐藏工具的有效性。如果接受了默认和序列化形式,以后又需要改变这个类的内部表示法,结果可能导致序列化形式的不兼容。
因此,相比较而言,设计良好的序列化形式也许会给类的演变带来好处。 - 代价二:增加了出现Bug和安全漏洞的可能性
通常对象的创建时通过构造器来创建的,序列化机制是一种语言之外的对象创建机制。反序列化机制也称“隐藏的构造器”,由于反序列化机制没有显示的构造器,故很容易忘记要确保:反序列化过程必须也要保证所有“由真正的构造器构造起来的约束关系”,并且不允许攻击者访问正在构造过程中的对象的内部信息。而依靠默认的序列化机制,很容易使对象的约束关系遭到破坏,以及遭受到非法访问。 - 代价三:随着类发行新的版本,相关的测试负担也增加了
当一个可序列化的类被修订的时候,很重要的一点是,要检查是否可以“在新版本中序列化一个实例,然后在旧版本中反序列化”,反之亦然。
(5)transient
transaction修饰符表明您这个实例域将从一个类的默认序列化形式中省略掉,可以加在类某个属性上,表示序列化时将该属性排除在外。
(6)反序列化默认值
当一个实例被反序列化的时候,其域被初始化为它的默认值:对于对象引用域,默认为null;对于数值基本域,默认为0;对于Boolean类型,默认为false。
(7)UID
- 序列化会使类的演变受到限制,这种限制的一个例子与流的唯一标识符有关,通常它也被称为序列版本UID。
- 每个可序列化的类都有唯一一个标识符与它相关联,如果你没有在一个名为serialversionUID的私有静态final的long域中显示的产生该标识号,系统将会自动地根据这个类来调用一个复杂的运算过程,从而在运行的时候产生该标识号。
- 这个自动产生的值,受到类的名称,它所实现的接口的名称,以及所有的公有的和受保护的成员的名称所影响。
- 如果通过任何方式改变了这些信息,自动产生的UID也会发生变化。无论选择哪种序列化形式。,都要为自己编写的每个可序列化的类声明一个显示的序列化版本UID,这样可以避免序列版本UID成为潜在的不兼容根源。而且也可避免在运行时通过一个高开销的计算过程产生一个序列版本UID,提高性能。