2012-04-20 28 views
2

序列化标识如何存储在对象的实例中?Java中的序列化版本uid

我们在Java中声明的序列化ID是静态字段;而静态字段不是序列化的。

然后应该有一些方法来存储静态最终字段。 java如何做到这一点?

回答

2

如果你看看java.io.ObjectStreamClass那里你可以看到它实际上是被序列化的。下面的方法:

java.io.ObjectOutputStream.writeClassDescriptor(ObjectStreamClass)

调用它调用下面的方法的方法:

java.io.ObjectStreamClass.getSerialVersionUID()

在调用哪个要么计算serialVersionUID或者使用一个类中声明,发现之前到以下方法:

java.io.ObjectStreamClass.getDeclaredSUID(Class)

所以看起来这个静态字段是一个例外,因为规则中没有对静态字段进行序列化。如何读取它here

3

serialVersionUID不存储在“序列化”对象的实例中,因为它是一个静态字段(它是类的一部分,而不是对象的一部分)。

因此,如果编译的字节码是实际定义的,那么它是stored,否则就是计算它。在java specification的词中:

如果类已经定义了serialVersionUID,它将从类中检索。如果serialVersionUID>未由类定义,则从虚拟机中类的定义计算。如果>指定的类不是可序列化或可外部化的,则返回null。

Stream Unique Identifiers section中,说明了用于这种计算的算法。

这一段值得注意(这就是为什么当实现Serializable的类没有明确定义serialVersionUID时IDE通常会显示警告)。

:强烈建议所有可序列化类中明确声明的serialVersionUID值,因为默认serialVersionUID的计算是对类的详细信息高度敏感,可能取决于编译器实现变化,从而可能导致在反序列化期间意外的serialVersionUID冲突,导致反序列化失败。

+0

@downvoter:你能评价你downvote? – jalopaba 2012-06-12 08:37:48

+0

“相对”downvote。必须确保Jiri的更好的答案在最前面(否则不会降低)。你完全忽略了这个问题的核心,那就是JVM如何知道序列化数据的版本(如果它的UID没有写入流中,那当然是,即使它是静态字段)。 – Thilo 2012-06-12 08:41:35

0

serialVersionUID是序列化运行时使用的特殊字段。这些都在Java文档中描述为java.lang.Serializable

2

串行版本UID未存储在对象中;它是一个静态字段,因此它存储在类定义中。发生什么事是,当你序列化一个对象时,关于它的类的信息也必须被存储;否则将无法对对象进行序列化。存储在类中的信息包括其名称和它的序列版本UID。

你可以在这里阅读整个协议:http://docs.oracle.com/javase/6/docs/platform/serialization/spec/protocol.html

总之,对于一个新的对象的条目都恰好是:

newObject: 
    TC_OBJECT classDesc newHandle classdata[] 

这里classDesc是类的描述符可以是一个宣言一个新的类,一个空引用或对之前声明的类的引用:

classDesc: 
    newClassDesc 
    nullReference 
    (ClassDesc)prevObject 

新类的声明建立了类的名称和序列版本UID,可用于以后参考它的手柄,以及其他信息编码为classDescInfo类:

newClassDesc: 
    TC_CLASSDESC className serialVersionUID newHandle classDescInfo