serialVersionUID 仅在反序列化入口处用于快速类版本比对,不参与实际字段解析;JVM 严格比对字节流中的 storedSUID 与当前类的 currentSUID,不等则立即抛 InvalidClassException。

serialVersionUID 不参与序列化数据的实际解析,它只在反序列化启动阶段被 JVM 用来做一次快速“类版本快照比对”。比对失败就立即抛 InvalidClassException,不进入字段赋值逻辑。
校验发生在反序列化入口处,且仅比对 long 值
当调用 ObjectInputStream.readObject() 时,JVM 会:
- 从字节流头部读出写入时保存的
serialVersionUID值(8 字节 long) - 获取当前类静态字段
serialVersionUID的运行时常量值 - 执行严格相等判断:
storedSUID == currentSUID - 不匹配则直接中断流程,不尝试解析后续字段、不调用
readObject方法、不触发构造器
没声明 serialVersionUID 时,JVM 自动计算的逻辑不可控
此时 JVM 调用 java.io.ObjectStreamClass.computeSerialVersionUID(),依据包括:
- 类名、超类名、实现的所有接口名
- 所有非 private / 非 static 字段的名称、类型、修饰符(
transient和static字段被忽略) - 所有非 private 方法的签名(名称、参数类型、返回类型、异常声明)
- 类的访问修饰符(
public、final等)
只要其中任一元素变化(比如改一个字段名、加一个 public 方法、换 JDK 编译),哈希结果就不同——这不是设计缺陷,而是刻意用结构指纹表达“类定义已变”。
声明了 serialVersionUID 后,校验逻辑不变,但控制权回到开发者手上
显式声明后,JVM 完全跳过自动计算步骤,只认你写的那个 long 值。这意味着:
- 加字段、改方法、增注释、换编译器——只要
serialVersionUID不变,校验就通过 - 是否真能成功反序列化,取决于 Java 序列化协议本身的兼容规则(如新增字段设默认值、删除字段被跳过)
-
serialVersionUID = 1L不是“万能兼容开关”,而是把“是否兼容”的决策权从 JVM 移交给代码维护者
校验不涉及语义、不检查字段含义,只认数字
JVM 不关心你把 int age 改成 String age,也不检查 transient 字段有没有配套的 readObject 实现。它只做一件事:比对两个 long 是否相等。其他所有兼容性问题(字段类型冲突、缺失自定义逻辑、父类变更等)都在校验通过后才暴露,有的报错,有的静默出错。

















