第11章 序列化

第74条:谨慎地实现Serializable接口


实现Serializable接口而付出的最大代价是,一旦一个类被发布,就大大降低了“改变这个类的实现”的灵活性。

第二个代价是,它增加了出现Bug和安全漏洞的可能性。

第三个代价是,随着类发行新的版本,相关的测试负担也增加了。

为了继承而设计的类应该尽可能少地去实现Serializable接口,用户的接口也应该尽可能少地继承Serializable接口。

千万不要认为实现Serializable接口会很容易。除非一个类在用了一段时间之后会被抛弃,否则,实现Serializable接口就是个很严肃的承诺,必须

认真对待。如果一个类是为了继承而设计的,则更加需要加倍小心。对于这样的类而言,在“允许子类实现Serializable接口”或“禁止子类实现Serializable

接口”两者之间的一个折衷设计方案是,提供一个可访问的无参构造器。这种设计方案允许(但不要求)子类实现Serializable接口。


第75条:考虑使用自定义的序列化形式


如果没有先认真考虑默认的序列化形式是否合适,则不要贸然接受。

即使你确定了默认的序列化形式是合适的,通常还必须提供了一个readObject方法以保证约束关系和安全性。

当你决定要将一个类做成可序列化的时候,请仔细考虑应该采用什么样的序列化形式。只有当默认的序列化形式能够合理地描述对象的逻辑状态时,

才能使用默认的序列化形式;否则就要设计一个自定义的序列化形式,通过它合理地描述对象的状态。你应该分配足够多的时间来设计类的序列化

形式,就好像分配足够多的时间来设计它的导出方法一样。正如你无法在将来的版本中去掉导出方法一样,你也不能去掉序列化形式中的域,它们

必须被永久地保留下去,以确保序列化兼容性(serialization compalibility)。选择错误的序列化形式对于一个类的复杂性和性能都会有永久的负面

影响。


第76条:保护性编写readObject方法


每当你编写readObject方法的时候,都要这样想:你正在编写一个公有的构造器,无论给它传递什么样的字节流,它都必须产生一个有效的实例。不要

假设这个字节流一定代表着一个真正被序列化过的实例。虽然在本条目的例子中,类使用了默认的序列化形式,但是,所有讨论到的有可能发生的问题

也同样适用于自定义序列化形式的类。下面以摘要的形式给出一些指导方针,有助于编写出更加健壮的readObject方法:

对于对象引用域必须保持为私有的类,要保护性地拷贝这些域中的每个对象。不可变类的可变组件就属于这一类别。

对于任何约束条件,如果检查失败,则抛出一个InvalidObjectException异常。这些检查动作应该跟在所有的保护性拷贝之后。

如果整个对象图在被反序列化之后必须进行验证,就应该使用ObjectInputValidation接口。

无论是直接方式还是间接方式,都不要调用类中任何可被覆盖的方法。


第77条:对于实例控制,枚举类型优先于reedResolve


如果依赖readResolve进行实例控制,带有对象引用类型的所有实例域则都必须声明为transient的。

你应该尽可能地使用枚举类型来实施实例控制的约束条件。如果做不到,同时又需要一个既可序列化又是实例受控(instance-controlled)的类,

就必须提供一个readResolve方法,并确保该类的所有实例域都为基本类型,或者是transient的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值