协慌网

登录 贡献 社区

什么是 serialVersionUID,我为什么要使用它?

当缺少serialVersionUID时,Eclipse 会发出警告。

可序列化类 Foo 不声明 long 类型的静态最终 serialVersionUID 字段

什么是serialVersionUID ,为什么它很重要?请显示缺少serialVersionUID会导致问题的示例。

答案

java.io.Serializable的文档可能与您将得到的解释一样好:

序列化运行时将每个可序列化类与版本号相关联,称为 serialVersionUID,在反序列化期间使用该版本号来验证序列化对象的发送方和接收方是否已加载与该序列化兼容的该对象的类。如果接收者为对象加载了一个类,该类具有与相应发送者类不同的 serialVersionUID,则反序列化将导致InvalidClassException 。可序列化类可以通过声明名为 “ serialVersionUID ” 的字段来显式声明其自己的 serialVersionUID,该字段必须是 static,final 和long类型:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于类的各个方面计算该类的默认 serialVersionUID 值,如 Java(TM)对象序列化规范中所述。但是, 强烈建议所有可序列化类显式声明 serialVersionUID 值,因为默认的 serialVersionUID 计算对类详细信息高度敏感,这些详细信息可能因编译器实现而异,因此在反序列化期间可能会导致意外的InvalidClassExceptions 。因此,为了保证跨不同 java 编译器实现的一致 serialVersionUID 值,可序列化类必须声明显式 serialVersionUID 值。强烈建议显式 serialVersionUID 声明尽可能使用 private 修饰符,因为此类声明仅适用于立即声明的类 - serialVersionUID 字段不适用于继承成员。

如果你的序列化只是因为你必须为了实现而序列化(谁关心你是否为 HTTPSession 序列化,例如...... 如果它存储与否,你可能不关心反序列化表单对象)那么你可以忽略这个。

如果您实际使用的是序列化,那么只有在您计划直接使用序列化存储和检索对象时才有意义。 serialVersionUID 表示您的类版本,如果您的类的当前版本与其先前版本不向后兼容,则应增加它。

大多数情况下,您可能不会直接使用序列化。如果是这种情况,请单击快速修复选项生成默认的可序列化 uid,不要担心。

我不能错过这个机会来插入 Josh Bloch 的书Effective Java (第 2 版)。第 11 章是 Java 序列化不可或缺的资源。

根据 Josh,自动生成的 UID 是基于类名,已实现的接口以及所有公共成员和受保护成员生成的。以任何方式更改任何这些都将更改serialVersionUID 。因此,只有当您确定不会将一个以上版本的类序列化时(无论是跨进程还是稍后从存储中检索),您都不需要弄乱它们。

如果你现在忽略它们,并且稍后发现你需要以某种方式更改类但是保持与旧版本类的兼容性,你可以使用 JDK 工具serialver类上生成serialVersionUID ,并显式设置在新班上。 (根据您的更改,您可能还需要通过添加writeObjectreadObject方法来实现自定义序列化 - 请参阅Serializable javadoc 或上述第 11 章。)