为什么编译器不自动设置serialVersionUID?

时间:2015-03-16 15:48:52

标签: java serialization

如果Serializable类没有定义serialVersionUID,则存在(!对于同一类!!)进行序列化的JVM计算与进行反序列化的JVM不同的版本的风险。建议的解决方案是使用serialver工具计算版本ID,并手动将其放入源代码。

这是愚蠢的恕我直言。如果没有在源代码中定义,javac自动计算serialVersionUID并放入字节码会好得多。

编译时是否存在与自动计算相关的问题?

我知道有类似编译器插件javac -Xplugin的东西。是否有可能创建自动化的插件?或者也许已经创建了这样的插件?

请不要使用Why isn't the serialVersionUID automatically generated?给我错误的重复。讨论了不同版本的类与序列化兼容的情况。我很有趣的情况是,同一个类应该总是通过序列化,不同版本的类应该失败。

3 个答案:

答案 0 :(得分:1)

因为ObjectInputStream和朋友一起做。它不是属于编译器的一部分功能,如果有的话它也不会解决任何问题。编译器不能做已经完成的任何事情。

  

我对同一个类总是要通过序列化并且不同版本的类失败的情况感兴趣。

那个案子已经有效了。无需解决方案。

答案 1 :(得分:1)

所以SerializableJavadoc声明:

  

如果可序列化类没有显式声明serialVersionUID,则序列化运行时将根据类的各个方面计算该类的默认serialVersionUID值,如Java(TM)对象序列化规范中所述。但是,强烈建议所有可序列化类显式声明serialVersionUID值,因为默认的serialVersionUID计算对类详细信息高度敏感,这些详细信息可能因编译器实现而异,因此在反序列化期间可能会导致意外的InvalidClassExceptions。因此,为了保证跨不同java编译器实现的一致的serialVersionUID值,可序列化的类必须声明一个显式的serialVersionUID值。

现在Java Serialization Specification州:

  

serialVersionUID是使用反映类定义的字节流的签名计算的。美国国家标准与技术研究院(NIST)安全散列算法(SHA-1)用于计算流的签名。前两个32位数量用于形成64位散列。 java.lang.DataOutputStream用于将原始数据类型转换为字节序列。输入到流的值由类的Java虚拟机(VM)规范定义。类修饰符可以包括ACC_PUBLIC,ACC_FINAL,ACC_INTERFACE和ACC_ABSTRACT标志;其他标志被忽略,不会影响serialVersionUID计算。同样,对于字段修饰符,在计算serialVersionUID值时仅使用ACC_PUBLIC,ACC_PRIVATE,ACC_PROTECTED,ACC_STATIC,ACC_FINAL,ACC_VOLATILE和ACC_TRANSIENT标志。对于构造函数和方法修饰符,仅使用ACC_PUBLIC,ACC_PRIVATE,ACC_PROTECTED,ACC_STATIC,ACC_FINAL,ACC_SYNCHRONIZED,ACC_NATIVE,ACC_ABSTRACT和ACC_STRICT标志。名称和描述符以java.io.DataOutputStream.writeUTF方法使用的格式编写。

因此,serialVersionUID在运行时基于"反映类定义的字节流的签名"来计算,因此基于编译器的输出。我相信这就是为什么他们说"强烈建议所有可序列化的类显式声明serialVersionUID值,因为默认的serialVersionUID计算对类详细信息非常敏感,可能会因编译器实现而异。"。 / p>

但无论如何,如果您使用相同的JDK运行时,相同的编译器等,则不应发生这种情况(除非JDK中存在错误)。

答案 2 :(得分:0)

  

如果Serializable类没有定义serialVersionUID,则存在风险   那个(!对于同一个类!)进行序列化的JVM会计算出来   与JVM不同的版本进行反序列化。

AFAIK指定了如何计算默认的serialVersionUID,并且每个兼容的JVM都应该正确实现这一点:http://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100

  

在doc中你链接的是一个句子:注意 - 强烈推荐   所有可序列化的类都显式声明serialVersionUID   值,因为默认的serialVersionUID计算是高度的   对类详细信息敏感,可能因编译器而异   实现,因此可能导致意外的serialVersionUID   反序列化过程中发生冲突,导致反序列化失败。所以   如果每个合规的JVM都应该正确实现这一点并且#39;有   不会发生意外的serialVersionUID冲突。但是有

不,对类详细信息非常敏感,可能会因编译器实现而异[>,但对于给定的类文件,类详细信息不会更改一次它被编译。但是如果使用两个不同的编译器编译相同的java文件,最终可能会得到两个具有不同默认serialVersionUID的类文件。

如果编译器将默认的serialVersionUID添加到类文件中,它就不会改变这方面的任何内容。