更改了实例变量的 Java 反序列化



我使用私有静态最终长序列化版本UID = 1L对学生类进行序列化并将其反序列化。当我更改 Student 类的实例变量并对其进行反序列化时,假设我将 name 实例变量更改为 fullName 并调用反序列化而不序列化这个修改后的学生类。 我仍然能够以反序列化方法进行以下转换

Studentstud=(Student) ois.readObject();

为什么它在转换过程中不抛出任何异常,因为传入的 deserilased 类和新的修改类是不同的。此外,除修改后的实例变量外,所有未修改的实例变量在反序列化后都恢复了值。 但是,当我从学生类中删除私有静态最终长序列化UID = 1L并反序列化时,我得到了java.io.InvalidClassException,这是可以理解的。 那么当 serialVersionUID 匹配时,它是否不检查类的任何其他属性? 这背后的概念是什么?

class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int id;
public String name() {
return name;
}
public void setname(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}

不是检查字段的状态(= 值),而是使用 serialVersionUID 检查类定义(= 类上可用的字段)。SerialVersionUID 是一个可选字段。如果您没有定义一个,JVM 将为您生成一个。因此,如果您有一个值为 1L 的序列化类,并尝试使用生成的序列化类(例如 -687991492884005033L)对其进行反序列化,则会导致 InvalidClassException。

从 Java 文档中:

序列化

运行时与每个可序列化类 a 相关联 版本号,称为 serialVersionUID,用于 反序列化以验证发送方和接收方是否序列化 对象已为该对象加载了与 关于序列化。如果接收器已为 具有与 对应的发送方的类,则反序列化将导致 InvalidClassException.可序列化类可以声明自己的 serialVersionUID 显式声明名为 "serialVersionUID",必须是静态的、最终的和长长的:

ANY-ACCESS-MODIFIER 静态最终长串行版本UID = 42L;

如果可序列化类未显式声明 serialVersionUID, 然后序列化运行时将计算默认值 该类的 serialVersionUID 值基于各个方面 类,如 Java(TM) 对象序列化中所述 规范。但是,强烈建议所有 可序列化类显式声明 serialVersionUID 值,因为 默认的 serialVersionUID 计算对类高度敏感 详细信息可能因编译器实现而异,并且可以 从而导致意外的无效类异常 反序列化。

关于 serialVersionUUID 计算的一个非常相关的答案是这个; 什么是 serialVersionUID,我为什么要使用它?

以下是 Discover the Secret of the Profiles 的引文,它应该可以回答您的问题。

粗体部分与您的示例非常相关。

。假设你创建了一个类,实例化它, 并将其写出到对象流中。那个扁平的物体位于 文件系统一段时间。同时,您更新类文件,也许添加一个新字段。当您尝试在 扁平的物体?

好吧,坏消息是会抛出一个异常—— 特别是java.io.InvalidClassException——因为所有 支持持久化的类会自动被赋予唯一的 标识符。如果类的标识符不等于平展对象的标识符,则将引发异常。但是,如果你真的考虑一下,为什么要把它扔掉 因为我添加了一个字段?该字段不能设置为其默认值吗 值,然后下次写出来?

是的,但这需要一点代码操作。标识符是 所有类的一部分都维护在名为serialVersionUID的字段中。 如果您希望控制版本控制,则只需提供手动串行版本UID字段,并确保它始终相同,否 不管你对类文件做了什么更改。您可以使用实用程序 随名为 serialver 的 JDK 发行版一起提供,看看它是什么 代码将是默认的(它只是对象的哈希代码 默认值)。

只要更改兼容,版本控制就可以很好地工作。 兼容的更改包括添加或删除方法或字段。不兼容的更改包括更改对象的层次结构或 删除可序列化接口的实现。一个完整的 Java 中给出了兼容和不兼容更改的列表 序列化规范。