Java中的序列化

4
在我们的代码中有一个实现Serializable接口的Java类。该类已经定义了serialVersionUUId。除此之外,我们还有另一个静态常量字符串sVersion,它是一个整数。该类实现了readObject和writeObject API。在readObject API中,它使用InputStream填充所有成员变量,在writeObject API中,它获取OutputStream并调用writeObject方法。
现在我需要为这个类添加一个布尔数组作为属性。我应该更改serialVersionUUID吗?如果更改/不更改版本ID会发生什么影响?最佳实践是什么?我正在尝试阅读Joshua Bloch的《Effective Java》,但需要一个简单易懂的快速答案。
谢谢。
2个回答

2
这个类实现了readObject和writeObject API。在readObject API中,它使用InputStream填充所有成员变量,在writeObject API中,它获取一个OutputStream并调用writeObject方法。
为什么?如果您根本不提供这些方法,那就是默认操作。[虽然我不知道您所说的“获取OutputStream”到底是什么意思,除非您指的是作为参数提供的OutputStream。]
然而,现在您在这里,在readObject()中,您只需要尝试读取新字段并捕获抛出的异常(OptionalDataException?),在writeObject()中写出额外的字段即可。
不要更改serialVersionUID。相反,您应该探索Serialization的广泛对象版本支持,以确保类现在确实与序列化不兼容,这根据规范非常难以实现;尝试诸如自定义read/writeObject()方法、readResolve/writeReplace()方法、serializableFields声明等方案,以确保流保持兼容性。更改实际的serialVersionUID是最后的手段,是绝望的建议。
在继续之前,您需要仔细查看对象序列化规范中的对象版本控制部分。序列化对于类演变有比大多数人意识到的更多支持,包括对本问题和他们链接到的问题的其他回答者。

谢谢提供链接。还有感谢你提到改变实际的serialVersionUID是“最后的手段” :) - Barry

0

如果有可能你最终会尝试反序列化一个不兼容的类实例,那么是的,你应该确实更新 serialVersionUID。另一方面,如果你的程序总是将数据序列化和反序列化而不保存到持久存储中,或者你的类与其调用者之间的协议仍然可以得到保证,那么你就不需要更改 serialVersionUID。

更多信息请参见https://dev59.com/Y3VC5IYBdhLWcg3wdw65#286254https://dev59.com/Y3VC5IYBdhLWcg3wdw65#285827


好的,我希望我的类也能与旧版本兼容。因此,我认为在阅读了您发送给我的链接后,不应更改versionId。但是,当读取对象方法尝试读取新的布尔数组时,我会收到OptionalDataException异常。 - Barry
如果有可能您最终会尝试对不兼容的类实例进行反序列化,那么是的,您肯定应该更新serialVersionUID。但这是一个循环论证。只有更改serialVersionUID才会使实例不兼容。仅添加字段是不够的。 - user207421
@EJP,您在回答中分享的链接讨论了“不兼容的更改”,这些更改会影响类与其调用者之间的契约,从而无法保持互操作性。这就是我所说的“不兼容”。 - rob
1
这个想法是避免完全使用“serialVersionUID”的政策,而不是轻率地递增它们。它们非常严重:字段类型更改、继承层次结构更改、类/包名称更改,一旦你知道了限制,所有这些都是可以避免的。正如我在我的回答中所说,“实际更改serialVersionUID是最后的手段,是绝望的建议”。 - user207421
@rob 我不知道你为什么要这样做。如果你超出了内置版本控制的范围,那么你应该采取我回答中提到的一个或多个措施,以保持序列化兼容性。 - user207421
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接