2008-09-03 162 views
7

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

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

回答

5

你可以在bug 4365406algorithm for computing serialVersionUID找到一些相关信息。基本上,在更改static成员的初始化时,编译器在引用System类的类中引入了新的static属性(我假设System类以前未在类中引用过),并且由于编译器引入了此属性不是私有的,它参与serialVersionUID计算。

道德:始终使用显式serialVersionUID,你会节省一些CPU周期和有些头疼:)

0

如果我正确读取规格,自动serialVersionUID不应该改变,如果你改变瞬态场的静态值。看看Spec的Chapter 5.6

然而,如果你仔细想想这一点 - 你通过序列化有static int MYINT = 3,当你再反序列化你希望得到相同的对象后面的类的对象开始,即用MYINT = 3。所以,如果你改变静态初始化,你会期望serialVersionUID改变,因为你不能再次获得相同的对象。

不管怎么说,记住这所有的序列化类,你可以控制serialVersionUID

private static final long serialVersionUID = 7526472295622776147L; 
0

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

只有在您确定这是一个安全更改的情况下,才能在该类的后续版本中明确设置serialVersionUID

2

自动的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实例通过Class.forName按需查找,并存储在一个静态字段中。正是这个静态字段破坏了serialVersionUID。从J2SE 5.0开始,ldc操作码的变体提供了对类文字的直接支持,消除了对合成域的需求。再次,所有这些都可以用javap -c显示出来。