2010-07-19 167 views
39

我知道我可以使用serialVersionUID来控制类的版本。而且我读到,我可以添加或删除字段,并且类仍然兼容,它只会使用默认值。我什么时候需要更改serialVersionUID?

必须我更改serialVersionUID?

+0

相关https://stackoverflow.com/questions/3678136/managing-several-versions-of-serialized-java-objects/14946099#14946099 – Gray 2017-12-14 17:55:21

回答

44

当对类的结构进行不兼容的更改时,理想情况下应该更改serialVersionUID字段的值。在Java Object Serialization Specification中列出了不兼容更改的完整列表 。

要进一步扩展,对类的不兼容更改将阻止反序列化机制创建对象的实例,因为流中的信息未映射到当前类定义。

+0

谢谢,很好的回答 – Kyle 2010-07-20 04:49:38

+1

不,不是。规范中列出的不兼容更改是那些尝试时会导致异常的更改。那些仅仅不映射到当前类定义的是*兼容*变化,并且还有一长串的变化。 – EJP 2014-08-19 09:24:30

+0

*为了进一步扩展,不兼容的更改会阻止反序列化机制创建实例*:这个答案不等于说我应该更改'serialVersionUID'来使反序列化机制抛出异常,即使它可以已经做到了,没有我的帮助,因为这是一个不兼容的变化,阻止上述机制的工作?如果是这样的话,我认为应该澄清一下这很有用。 (我在这里怀疑是因为[EJP的回答](https://stackoverflow.com/a/3288280/1036728)更有意义。) – antak 2018-03-05 07:02:28

3

如果您在Serializable类中未指定serialVersionUID字段,则Java编译器将为您指定一个字段 - 本质上它是类名称,接口名称,方法和类字段的散列。但是,随时可以更改方法,因此如果需要更改存储类的反序列化方式,可以覆盖readObject方法。但是,如果您在代码中指定了serialVersionUID字段,即使您做出不兼容的更改(即运行时会导致异常),编译器也不会覆盖该更改 - 您的IDE或编译器不会给出警告。 (编辑 - 谢谢EJP)如果您想轻松地检查编译器如何查看某些更改,Eclipse等IDE可以为您插入编译器的UID。

如果您经常进行更改,请保留旧版本的磁盘文件以测试反序列化。您可以编写单元测试来尝试读入旧文件,并查看它是否有效或者是否完全不兼容。

一个告诫,我亲身体验过与Serializable类最初打算用于长期存储的设计不当的痛苦。例如,将GUI元素存储在磁盘上,而不是在需要时创建它们。问问自己,如果Serializable确实是保存数据的最佳方式。

+0

+1用于指出存储数据的Serializable问题,特别是在使用你自己的类(JDK中的类至少足够稳定)。 – Thilo 2010-07-20 06:42:32

+0

'...不兼容的更改会导致运行时异常' - 您需要澄清这一点。你会得到IOExceptions,而不是RuntimeExceptions。 – EJP 2010-07-21 23:57:19

+0

@EJP你说得对,我可以说更好。您将在运行时获得IOEXception /正是我的意思 - 您的IDE或编译器不会提前提醒您。 – 2010-07-22 22:15:38

16

每当你改变课程时,经常重复的关于改变serialVersionUID的咒语是完全的,完全是无稽之谈。请参阅this Sun article,它们在其网站上重新发布,并在收购后迁移到Oracle技术网络。

你应该改变serialVersionUID只有当你刻意要打破兼容所有现有的序列化,例如,当改变你的类将使它所以语义不同,你别无选择 - 在这种情况下,你应该真的多次想到你实际上在做什么。

在所有其他情况下,你应该胸围你锅炉试图使用自定义readObject()/writeObject()和/或writeReplace()/readResolve()方法和/或serialFields注解,这样就可以继续从那些现有的序列化阅读的对象。一旦你打破了,你是在头痛,真是噩梦。

+0

该URL不可用。你能更新它吗? – 2015-04-24 15:37:19

+1

这个答案可以通过完全陈述你不同意的内容,或者你认为你的链接文章所倡导的内容来改善。阅读这篇文章,我看不到太阳是什么“不同意”。 – DavidS 2015-12-03 23:27:13

+0

如果我为班级添加了一个新字段,该怎么办?此更改仍然兼容:不会抛出异常。但该字段不包含任何信息,因此在语义上它不兼容。在这种情况下,我应该增加UID吗? – damluar 2016-11-02 11:31:51

-1

您可以将serialiVersionUID设置为类的生命期相同的值。 (并非总是一个好主意)注意:如果需要,可以使用readObject/writeObject实现自己的序列化版本检查策略,并保持UID不变。

您必须改变它的唯一时间是如果您已经将某些数据序列化到文件并且您想要读取它。如果由于任何原因它已经改变,你必须将serialiVersionUID设置为文件中的版本,以期望能够读取数据。

+0

这是一个迹象,你不应该改变它在第一个地方。 – EJP 2010-08-14 06:52:00

相关问题