![Java核心技术·卷Ⅱ:高级特性(原书第10版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/937/34339937/b_34339937.jpg)
上QQ阅读APP看书,第一时间看更新
2.4.4 序列化单例和类型安全的枚举
在序列化和反序列化时,如果目标对象是唯一的,那么你必须加倍当心,这通常会在实现单例和类型安全的枚举时发生。
如果你使用Java语言的enum结构,那么你就不必担心序列化,它能够正常工作。但是,假设你在维护遗留代码,其中包含下面这样的枚举类型:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/077-3-i.jpg?sign=1739264098-bjj4Yr8I1nkZMQBjiTcubDCPQpniQX1C-0-df48190e39b5dfe392e4b7c43aeb2a4c)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/078-i.jpg?sign=1739264098-pXcJQ46b371egVtwreQVm8PXNR4X4mDt-0-ade786577c5b05b70dd5a653fde613b7)
这种风格在枚举被添加到Java语言中之前是很普遍的。注意,其构造器是私有的。因此,不可能创建出超出Orientation.HORIZONTAL和Orientation.VERTICAL之外的对象。特别是,你可以使用==操作符来测试对象的等同性:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/078-5-i.jpg?sign=1739264098-a5nPpHEYW1Zd4su5gZqmaeiE75If6i6z-0-949feccee0fcaf2f9c0169703a35e178)
当类型安全的枚举实现Serializable接口时,你必须牢记存在着一种重要的变化,此时,默认的序列化机制是不适用的。假设我们写出一个Orientation类型的值,并再次将其读回:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/078-2-i.jpg?sign=1739264098-6SaQcsu7Is97vC0L4MNhPNkEh1by919Y-0-4c455f02ea3c2d3679bae08d4278ff74)
现在,下面的测试:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/078-3-i.jpg?sign=1739264098-4TbQCRGElRBn0A6YfWC99z91wnlRx97j-0-898947ae2c49bb458c2e2120e4093820)
将失败。事实上,saved的值是Orientation类型的一个全新的对象,它与任何预定义的常量都不等同。即使构造器是私有的,序列化机制也可以创建新的对象!
为了解决这个问题,你需要定义另外一种称为readResolve的特殊序列化方法。如果定义了readResolve方法,在对象被序列化之后就会调用它。它必须返回一个对象,而该对象之后会成为readObject的返回值。在上面的情况中,readResolve方法将检查value域并返回恰当的枚举常量:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/078-4-i.jpg?sign=1739264098-FevPOvTqLdapzHIJQ3a6Ziem3dUoVA10-0-49914025c1621cff4f5a7f17096dd5a0)
请记住向遗留代码中所有类型安全的枚举以及向所有支持单例设计模式的类中添加readResolve方法。