序列化(serialization)。

谨慎的实现Serializable接口

千万不要认为实现Serializable接口会很容易。除非一个类在用了一段时间之后就会被抛弃,否则,实现Serializable接口就是个很严肃的承诺,必须认真对待。如果一个类是为了继承而设计的,则更加需要加倍小心。对于这样的类而言,在“允许子类实现Serializable接口”或“禁止子类实现Serializable接口”两者之间的一个折中设计方案是,提供一个可访问的无参构造器。这种设计方案允许(但不要求)子类实现Serializable接口。

考虑使用自定义的序列化形式

当你决定要将一个类做成可序列化的时候,请仔细考虑应该采用什么样的序列化形式。只有当默认的序列化形式能够合理的描述对象的逻辑状态时,才能使用默认的序列化形式;否则就要设计一个自定义的序列化形式,通过它合理的描述对象的状态。你应该分配足够多的时间来设计类的序列化形式,就好像分配足够多的时间来设计它的导出方法一样。正如你无法再将来的版本中去掉导出方法一样,你也不能去掉序列化形式中的域;他们必须被永久的保留下去,以确保序列化兼容性。选择错误的序列化形式对于一个类的复杂性和性能都会有永久的负面影响。

保护性的编写readObject方法

每当你编写readObject方法的时候,都要这么想:你正在编写一个公有的构造器,无论给它传递什么样的字节流,它都必须产生一个有效的实例。不要假设这个字节流一定代表着一个真正被序列化过的实例。下面以摘要的形式给出一些指导方针,有助于编写出更加健壮的readObject方法:

  • 对于对象引用域必须保持为私有的类,要保护性的拷贝这些域中的每个对象。不可变类的可变组件就属于这一类别。
  • 对于任何约束条件,如果检查失败,则抛出一个InvalidObjectException异常。这些检查动作应该跟在所有的保护性拷贝之后。
  • 如果整个对象图在被反序列化之后必须进行验证,就应该使用ObjectInputValidation接口。
  • 无论是直接方式还是间接方式,都不要调用类中任何可被覆盖的方法。

对于实例控制,枚举类型优先于readResolve

你应该尽可能地使用枚举类型来实施实例控制的约束条件。如果做不到,同步时又需要一个既可序列化又是实例控制的类,就必须提供一个readResolver方法,并确保该类的所有实例域都为基本类型,或者是transient的。

考虑用序列化代理代替序列化实例

每当你发现自己必须在一个不能被客户端扩展的类上编写readObject或者writeObject方法的时候,就应该考虑使用序列化代理模式。要想稳健的将带有重要约束条件的对象序列化时,这种模式可能是最容易的办法。

猜你喜欢

转载自blog.csdn.net/en_joker/article/details/81430273
今日推荐