我有一组可以读取和写入磁盘的对象。但是现在我想在我的类中添加一个成员变量。如果我添加成员变量,我会得到一个类不兼容错误,我将无法读取我的序列化对象。有没有一种方法可以修改用于序列化的类的成员变量,而不会失去读取持久对象的能力......或者一种将持久对象转换为新类的简单方法?
5 回答
如果我添加成员变量,我会得到一个类不兼容的错误。
不,你不会,除非你忘记为serialVersionUID
类定义一个值。如果您这样做了,请使用该类的原始serialver
版本上的实用程序来告诉您要添加什么。
向可序列化的类添加字段是完全良性的。请参阅对象序列化规范的版本控制章节,了解在破坏其在序列化下的兼容性之前可以对类执行的操作的完整详细信息。
SO的这篇文章应该可以回答您的问题。它甚至解释了如何找到编译器自动创建的串行版本,如果你没有指定它(serialver
在引用页面中找到)。旧文章仍然可以很有趣...对于不耐烦的人来说:
- 序列化会自动处理新成员或删除的成员,前提是 serialversion 不会改变
- IDE或者
serialver
JDK的工具可以给你编译器自动生成的序列号,如果你没有指定的话
所以你只需要找到这个序列版本,添加魔法字段static final long serialVersionUID = xx
,因为你只添加一个成员变量,一切都应该没问题。
(引用的帖子是谷歌的第一个答案java serialization multiple versions
)
首先,Java 序列化不适用于对象持久性,因为您遇到的问题很突出。
然而,有一个解决方法(这将让你在短期内开始) - 将 a 添加serialVersionUID
到你的类中,并且当你以影响其序列化形式的方式修改类时不要更改。
恕我直言,这是serialVersionUID
对serialVersionUID
@EJP 答案中的链接中有详细说明),因为字段设置为默认值,这意味着当结果不是用户期望的并且您有一个比序列化错误更难找到的细微错误时,您的系统可能不会抛出异常。
所有类都得到一个serialVersionUID
- 如果您没有声明一个,则由序列化运行时生成一个。通过声明serialVersionUID
你告诉序列化运行时,不要生成一个,因为你知道类的序列化形式与之前构建的兼容,例如,如果你toString
在初始编译后添加了一个需要重建或已经采取的方法确保不同版本正确序列化的步骤(同样,@EJP 答案中的链接)。
添加类变量后,确保发送方和接收方都有这个类的新版本,它们正在序列化/反序列化。那应该可以解决您的问题。
当然,还要重新生成磁盘/序列化数据。
顺便说一句,增加 serialVersionUID 是一个很好的做法。序列化使用它来确保两端的类相同,并且保存的数据与当前类兼容。
====
在看了一些评论之后,我想补充一下为什么 serialVersionUID 可能是一件坏事。最重要的是,它必须手动维护。在有严格程序的商店里,这不是问题。然而,简单地添加一个然后忽略它或一半时间更新它会导致错误的安全感。它似乎有帮助,但事实并非如此。
这里有一些想法:
- 如果 Serialiable 类没有 serialVersionUID,编译器会发出警告,因此添加一个。允许警告累积会使它们毫无用处。
- 创建一个标准,然后遵循它。选择不更新值是有效的,但这意味着您必须找到另一种方法来保持系统之间的类匹配。
- 如果您不打算在类属性更改时更新该值,则将该值设置为 -1 作为指示符。