跨不同 JVM 的 Java 标准库中的 SerialVersionUID
SerialVersionUID in the Java standard library across different JVMs
根据此处对 SerialVersionUID 的描述:https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100,似乎有必要在您创建的任何 classes 中始终包含 SerialVersionUID,以便用于序列化的 JVM 和用于反序列化的不同 JVM不会自动分配它们自己的 SerialVersionUID,由于 JVM 的差异,它们可能彼此不同。这对于控制我自己的 classes 的反序列化非常有效,但是如果我想确保标准库中用 JVM A 序列化的 classes 可以被 JVM B 反序列化怎么办?
Map<Integer, String> myMap = new HashMap<>();
HashMap 定义了一个 SerialVersionUID。但是:
- 由于 HashMap 存在于 java 标准库中,我是否提供任何形式的保证,即如果我使用 JVM A 序列化此 HashMap,那么 JVM B 将能够反序列化它?即,是否允许 JVM B 指定与 JVM A 不同的 SerialVersionUID,至少如果 B 只是 A 的次要版本升级?
如果不能保证标准库 classes,使用 SerialVersionUID 是否真的只确保对你自己的 classes 进行适当的反序列化,而这些 classes 永远不会触及 java标准库?例如,class 看起来像这样:
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 中可能不同,对吧?
可能是的,你是对的。
实际上这在我们身上发生过一段时间 swing
classes(我真的不记得具体是哪个),但是在 jdkX
和 [=41] 上连载=] 他们在 jdkX+1
上(那是很久以前的事了,很抱歉错过了这些细节),事情开始与 InvalidClassException
分道扬镳。我们当时支付了支持并提出了一个问题 - 回应是,嗯,那些 class(es) 以这样一种方式改变了,以至于不可能正确地反序列化它们 - 你被这个版本所困,或升级到 jdk+1
并使用它。从那以后,我再也没有发生过,一次也没有。
总的来说,我认为这也是使序列化变得困难的原因。你必须维护这样一个过程,以便从序列化的角度来看,未来版本的更改可以与以前的版本相关并兼容。
另一方面,HashMap
有一种非常聪明的方法来序列化它的数据。它序列化(除其他外,如 load_factor
等) 仅 它是键和值 - 没有别的。所以无论实现是否改变,它们都可能是 de-serialzied。出于这个原因,一些不需要的字段被标记为临时的,例如:
transient int modCount;
transient Set<Map.Entry<K,V>> entrySet;
想法是它应该序列化数据与结构。
例如,如果 HashMap
以序列化中断 jdk-11
的方式进行更改,这会让很多开发人员生气,我怀疑这是否会被采用(除非 真的需要)
根据此处对 SerialVersionUID 的描述:https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100,似乎有必要在您创建的任何 classes 中始终包含 SerialVersionUID,以便用于序列化的 JVM 和用于反序列化的不同 JVM不会自动分配它们自己的 SerialVersionUID,由于 JVM 的差异,它们可能彼此不同。这对于控制我自己的 classes 的反序列化非常有效,但是如果我想确保标准库中用 JVM A 序列化的 classes 可以被 JVM B 反序列化怎么办?
Map<Integer, String> myMap = new HashMap<>();
HashMap 定义了一个 SerialVersionUID。但是:
- 由于 HashMap 存在于 java 标准库中,我是否提供任何形式的保证,即如果我使用 JVM A 序列化此 HashMap,那么 JVM B 将能够反序列化它?即,是否允许 JVM B 指定与 JVM A 不同的 SerialVersionUID,至少如果 B 只是 A 的次要版本升级?
如果不能保证标准库 classes,使用 SerialVersionUID 是否真的只确保对你自己的 classes 进行适当的反序列化,而这些 classes 永远不会触及 java标准库?例如,class 看起来像这样:
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 中可能不同,对吧?
可能是的,你是对的。
实际上这在我们身上发生过一段时间 swing
classes(我真的不记得具体是哪个),但是在 jdkX
和 [=41] 上连载=] 他们在 jdkX+1
上(那是很久以前的事了,很抱歉错过了这些细节),事情开始与 InvalidClassException
分道扬镳。我们当时支付了支持并提出了一个问题 - 回应是,嗯,那些 class(es) 以这样一种方式改变了,以至于不可能正确地反序列化它们 - 你被这个版本所困,或升级到 jdk+1
并使用它。从那以后,我再也没有发生过,一次也没有。
总的来说,我认为这也是使序列化变得困难的原因。你必须维护这样一个过程,以便从序列化的角度来看,未来版本的更改可以与以前的版本相关并兼容。
另一方面,HashMap
有一种非常聪明的方法来序列化它的数据。它序列化(除其他外,如 load_factor
等) 仅 它是键和值 - 没有别的。所以无论实现是否改变,它们都可能是 de-serialzied。出于这个原因,一些不需要的字段被标记为临时的,例如:
transient int modCount;
transient Set<Map.Entry<K,V>> entrySet;
想法是它应该序列化数据与结构。
例如,如果 HashMap
以序列化中断 jdk-11
的方式进行更改,这会让很多开发人员生气,我怀疑这是否会被采用(除非 真的需要)