仅更改方法时出现本地 class 不兼容错误

Local class incompatible error when only a method has changed

我刚遇到 "WTF" 类错误:我更新了 classe 的一个方法并添加了一个方法。在 运行 我的程序之后,当程序试图打开和反序列化最近保存的数据时(在方法更改之前),弹出的是:

java.io.InvalidClassException: cz.autoclient.settings.Settings; local class incompatible: stream classdesc serialVersionUID = 2404650814140543454, local class serialVersionUID = 4256355437298300223

根据 java 文档所说的,java 方法没有被序列化。那么为什么 serialVersionUID 也考虑了 class 方法呢?

既然 Java 程序员似乎对到处使用 getters 和 setter 如此疯狂,为什么不能为 serialVersionUID 创建 getter 以便我可以实现自己的只计算属性的算法吗?

serialVersionUID can be overriden,但只有 static final long serialVersionUID 值,这要求我在更改 class 的属性时记得更改它。

Oracle docs表示如果你不提供serialVersionUID,编译器会为你生成一个。

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.

并根据 Java Object Serialization Specification section 5.1

Versioning raises some fundamental questions about the identity of a class, including what constitutes a compatible change. A compatible change is a change that does not affect the contract between the class and its callers.

这里发生的事情是,编译器已决定您的代码的两个版本之间的差异需要一个新的 serialVersionUID。如果您觉得 Object(1) 和 Object(2) 的实例中包含的状态可以互换,您应该通过手动设置 serialVersionUID 并在这些更改之间保持相同来管理它。

是的,您必须手动管理它,并在更改管理 class 内部状态的机制时更改它。

不过请注意,如果 public 方法发生了变化,您应该考虑 class 的原始版本是否满足与新版本相同的期望。如果您希望将先前序列化状态中包含的数据加载到 class 的新版本中,可以使用静态构造函数方法用兼容的旧状态初始化新版本(新行为)。

根据 java 的文档,他们建议尽可能使用自定义 serialVersionUID,因为默认算法将采用 class 实现细节,据说结果因 JVM 实现而异。

Java 用来生成 serialVersionUIDdefault algorithm 似乎也在考虑非私有方法(第 7 步)。这解释了如果您在实施中使用默认 serialVersionUID 时出现的异常。

编辑: 正如您所建议的那样,如果我们可以自己实现一个方法来执行此操作,而不是将 serialVersionUID 重写为 static final long,那就太好了。但我猜他们不允许这样做,因为如果允许的话,这种方法的错误实现可能会使 serialVersionUID.

的整个目的无效