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

问题

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

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

什么是“serialVersionUID”?为什么它很重要?请展示缺少serialVersionUID会导致问题的例子。


#1 热门回答(1881 赞)

对于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计算对类详细信息高度敏感,这可能因编译器实现而异,因此在反序列化期间可能会导致意外的InvalidClassException。因此,要确保跨不同的java编译器实现保持一致的serialVersionUID值,可序列化的类必须声明显式的serialVersionUID值。还强烈建议显式serialVersionUID声明尽可能使用private修饰符,因为这些声明仅适用于立即声明的类 - serialVersionUID字段作为继承成员是无用的。


#2 热门回答(411 赞)

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

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

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


#3 热门回答(255 赞)

我不能放弃这个机会来插入乔希布洛赫的书Effective Java(第2版)。第11章是Java序列化不可或缺的资源。

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

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