Java中的序列化版本uid
序列化ID如何存储在对象的实例中?
我们在Java中声明的序列化ID是静态字段;静态字段不是序列化的。
应该有一些方法来存储静态最终字段。 java是如何做到的?
serialVersionUID不存储在“序列化”对象的实例中,因为它是一个静态字段(它是类的一部分,而不是对象的一部分)。
因此,如果实际定义了它,则将其stored
在编译的字节码中,否则将对其进行计算。 在java规范的话中:
如果类已定义serialVersionUID,则从类中检索它。 如果serialVersionUID>未由类定义,则根据虚拟机中类的定义计算。 如果>指定的类不可序列化或可外部化,则返回null。
在流唯一标识符部分中 ,解释了用于这种计算的算法。
这一段是值得注意的(这就是为什么当实现Serializable的类没有明确定义serialVersionUID时,IDE通常会显示警告)。
注意 :强烈建议所有可序列化类显式声明serialVersionUID值,因为默认的serialVersionUID计算对类细节高度敏感,这些细节可能因编译器实现而异 ,因此在反序列化期间可能导致意外的serialVersionUID冲突,从而导致反序列化失败。
如果你查看java.io.ObjectStreamClass
,你会发现它实际上是序列化的。 以下方法:
java.io.ObjectOutputStream.writeClassDescriptor(ObjectStreamClass)
调用一个调用以下方法的方法:
java.io.ObjectStreamClass.getSerialVersionUID()
其中既可以计算serialVersionUID
也可以使用在类中声明的并在调用以下方法之前找到的:
java.io.ObjectStreamClass.getDeclaredSUID(Class)
因此,这个静态字段似乎是静态字段未被序列化的规则的例外。
这里描述了如何阅读它。
串行版本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
serialVersionUID
是序列化运行时使用的特殊字段。 这些都在Java Doc中描述了java.lang.Serializable