在 Java 中,静态和瞬态字段不是序列化的。但是,我发现静态字段的初始化会导致生成的serialVersionUID发生更改。例如, static int MYINT = 3; 导致serialVersionUID改变。在此示例中,这是有道理的,因为该类的不同版本将获得不同的初始值。为什么任何初始化都会改变serialVersionUID?例如, static String MYSTRING = System.getProperty("foo"); 也会导致serialVersionUID发生变化。

具体来说,我的问题是为什么使用方法进行初始化会导致serialVersionUID发生变化。我遇到的问题是我添加了一个使用系统属性值 (getProperty) 初始化的新静态字段。该更改导致远程调用出现序列化异常。

有帮助吗?

解决方案

您可以在以下位置找到一些相关信息 错误 4365406 并在 计算算法 序列号版本UID. 。基本上,当改变你的初始化时 static 成员与 System.getProperty(), ,编译器引入了一个新的 static 你的类中的属性引用了 System 类(我假设 System 类以前在您的类中未引用),并且由于编译器引入的该属性不是私有的,因此它参与 serialVersionUID 计算。

道德: :始终使用显式 serialVersionUID, ,您将节省一些 CPU 周期并减少一些麻烦:)

其他提示

自动serialVersionUID是根据类的成员计算的。可以使用 Sun JDK 中的 javap 工具显示类文件的这些信息。

在问题中提到的情况下,添加/删除的成员是静态初始化程序。这在类文件中显示为 ()V。可以使用 javap -c 反汇编该方法的内容。您应该能够识别出 System.getProperty("foo") 调用以及对 MYSTRING 的赋值。然而,类文件直接支持字符串文字(或 Java 语言规范定义的任何编译时常量)的赋值,因此无需静态初始化程序。

针对 J2SE 1.4(使用 -source 1.4 -target 1.4)或更早版本的代码的常见情况是旧 Class 实例的静态字段,这些实例在源代码 (MyClass.class) 中显示为类文字。根据需要使用 Class.forName 查找 Class 实例,并将其存储在静态字段中。正是这个静态字段破坏了serialVersionUID。从 J2SE 5.0 开始,ldc 操作码的一个变体提供了对类文字的直接支持,从而不再需要合成字段。同样,所有这些都可以通过 javap -c 显示。

如果我正确阅读了规格,则会自动 serialVersionUID 如果更改瞬态静态字段的值,则不应更改。看一眼 第5.6章 规范的。

然而, ,如果你想一下这一点 - 你首先序列化一个具有 static int MYINT = 3, ,当您反序列化该类时,您希望得到相同的对象,即 MYINT = 3. 。因此,如果您更改静态初始化,您会期望 serialVersionUID 进行更改,因为您无法再次取回相同的对象。

无论如何, ,将其保留在所有可序列化的类中,您可以控制 serialVersionUID:

private static final long serialVersionUID = 7526472295622776147L;

我更新了问题以使其更加清晰。我明白为什么用文字初始化会改变 serialVersionUID 但不是为什么动态初始化会改变它。如果您使用方法进行初始化,那么该值当然可能始终不同。

设置 serialVersionUID 仅当您确定这是一个安全的更改时,才可以在该类的后续版本中显式地进行更改。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top