Java序列化:readObject()与readResolve()

For*_*age 125 java singleton serialization

有效Java和其他资源一书提供了一个很好的解释,说明在使用可序列化的Java类时如何以及何时使用readObject()方法.另一方面,readResolve()方法仍然有点神秘.基本上我发现的所有文件要么只提到两个中的一个,要么仅单独提及.

仍未得到答复的问题是:

  • 这两种方法有什么区别?
  • 何时应该实施哪种方法?
  • 应该如何使用readResolve(),特别是在返回什么方面?

我希望你能对这件事有所了解.

Mic*_*ers 131

readResolve用于替换从流中读取的对象.我见过的唯一用途就是强制执行单身人士; 读取对象时,将其替换为单例实例.这确保了没有人可以通过序列化和反序列化单例来创建另一个实例.

  • 我发现这个答案略显不足,因为它没有提到"瞬态"字段.`readResolve`用于在读取后解析*对象.一个示例用法可能是一个对象包含一些可以从现有数据重新创建的缓存,而不需要序列化; 缓存的数据可以声明为"transient",而`readResolve()`可以在反序列化后重建它.这样的事情是这种方法的用途. (17认同)
  • Josh Bloch讨论了有效Java第二版中断的条件.项目77.他在几年前在谷歌IO中给出的这个演讲中提到了这一点(有时候在谈话结束时):http://www.youtube.com/watch?v = pi_I7oD_uGI (6认同)
  • 恶意代码(甚至数据)有很多方法可以解决这个问题. (3认同)
  • @JasonC你的评论"这样的事情[瞬态处理]是这个方法_is for_"的误导.请参阅Java文档中的"Serializable":它说"当从流中读取实例时需要指定**替换**的类应该实现这个[`readResolve`]特殊方法......". (2认同)
  • readResolve方法也可以用在一个角落的情况下,假设你已经序列化了很多对象并将它们存储在数据库中.如果在以后的某个时间点,您希望将该数据迁移到新格式,则可以在readResolve方法中轻松实现. (2认同)

AZ_*_*AZ_ 40

readResolve当方法被称为ObjectInputStream已读取来自流的对象,并准备将其返回给调用者.ObjectInputStream检查对象的类是否定义了readResolve方法.如果定义了readResolve方法,则调用该方法以允许流中的对象指定要返回的对象.返回的对象应该是与所有用途兼容的类型.如果它不兼容,ClassCastException则在发现类型不匹配时将抛出a .


Tom*_*ine 28

readResolvewriteReplace返回之后调用(相反地readObject在之前调用writeObject并且可能在另一个对象上调用).方法返回的对象替换readResolve返回给用户readObject的对象以及对流中对象的任何进一步的后向引用.它主要用于串行代理(参见Effective Java,2nd Ed,IIRC).


end*_*ess 9

readResolve可用于更改通过readObject方法序列化的数据.例如,xstream API使用此功能初始化一些不在XML中反序列化的属性.

http://x-stream.github.io/faq.html#Serialization

  • 接受的答案表明readResolve用于替换对象.此答案提供了有用的附加信息,可用于在反序列化期间修改对象.给出了XStream作为示例,而不是唯一可能发生这种情况的库. (5认同)

arj*_*hta 7

readObject() 是ObjectInputStream类中已有的方法。在反序列化时读取对象 readObject 方法在内部检查正在反序列化的类对象是否具有 readResolve 方法,如果存在 readResolve 方法,则它将调用 readResolve 方法并返回相同的实例。

因此,编写 readResolve 方法的意图是实现纯单例设计模式的好做法,在这种模式下,没有人可以通过序列化/反序列化来获得另一个实例。


Pr0*_*ean 5

readResolve用于何时可能需要返回现有对象,例如因为您正在检查应该合并的重复输入,或者(例如,在最终一致的分布式系统中),因为它是一个可能在您意识到之前到达的更新任何旧版本.