跨不同 JVM 的 Java 标准库中的 SerialVersionUID

Posted

技术标签:

【中文标题】跨不同 JVM 的 Java 标准库中的 SerialVersionUID【英文标题】:SerialVersionUID in the Java standard library across different JVMs 【发布时间】:2018-08-09 22:49:20 【问题描述】:

根据此处对 SerialVersionUID 的描述:https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100,似乎有必要在您创建的任何类中始终包含 SerialVersionUID,以便用于序列化的 JVM 和用于反序列化的不同 JVM 不会自动分配它们自己的 SerialVersionUID,由于JVM的差异,它们有可能彼此不同。这对于控制我自己的类的反序列化效果很好,但是如果我想确保标准库中用 JVM A 序列化的类可以被 JVM B 反序列化怎么办?

Map<Integer, String> myMap = new HashMap<>();

HashMap 定义了一个 SerialVersionUID。但是:

既然 HashMap 存在于 java 标准库中,我是否提供了任何形式的保证,如果我用 JVM A 序列化这个 HashMap,JVM B 将能够反序列化它?也就是说,是否允许 JVM B 指定与 JVM A 不同的 SerialVersionUID,至少如果 B 只是从 A 升级的次要版本?

如果标准库类不能保证,那么使用 SerialVersionUID 是否真的只能确保您自己的类从不接触 java 标准库的正确反序列化?例如,一个如下所示的类:

public class NewClass implements Serializable

    private static final long serialVersionUID = 1L;

    private final Map<Integer, String> myMap;

    public NewClass()
    
        this.myMap = new HashMap<>();
    

很容易失败,因为反序列化依赖于具有相同 SerialVersionUID 的 HashMap,这在不同的 JVM 中可能会有所不同,对吧?

【问题讨论】:

【参考方案1】:

可能是的,你是对的。

实际上这发生在我们之前的一些 swing 类(我真的不记得到底是哪个),但在 jdkX 上序列化并在 jdkX+1 上对它们进行反序列化(那真的很长前段时间,很抱歉错过了这些细节),事情开始与InvalidClassException 发生冲突。我们当时已经支付了支持并打开了一个问题 - 响应是,这些类以这样的方式发生了变化,以至于无法正确反序列化它们 - 你被这个版本卡住了,或者升级到jdk+1 并使用它。从那以后没有发生在我身上,一次也没有。

一般来说,我认为这也是让序列化变得困难的原因。您必须维护这样一个过程,以便从序列化的角度来看,未来版本中的更改可以与以前的版本相关并兼容。

另一方面,HashMap 有一种非常聪明的方法来序列化它的数据。它序列化(除其他外,如load_factor 等)它是键和值 - 仅此而已。因此,无论实现是否发生变化,它们都可能被反序列化。出于这个原因,一些不需要的字段被标记为瞬态,例如:

 transient int modCount;
 transient Set<Map.Entry<K,V>> entrySet;

这个想法是它应该序列化数据与结构。


如果HashMap 以这样的方式发生变化,例如,序列化会在jdk-11 中中断,这会让很多开发人员生气,我怀疑这是否会成为一条路径(除非真的 需要)

【讨论】:

每个 Swing 类在 Javadoc 中都有一个警告,说明可能跨 JDK 版本的序列化不兼容。 @EJP 哦!现在这是有道理的......谢谢你

以上是关于跨不同 JVM 的 Java 标准库中的 SerialVersionUID的主要内容,如果未能解决你的问题,请参考以下文章

跨语言共享环境变量

Java标准库中的键值,键值类[重复]

JVM - 1. Java虚拟机梗概,那些你不知道的VM

技术分享 | JVM - 1. Java虚拟机梗概,那些你不知道的VM

节:跨平台的语言Java和跨语言的平台JVM

节:跨平台的语言Java和跨语言的平台JVM