我们有时候在写代码的时候,对于一个需要序列化的类,如果不去写 serialVersionUID
,编译器可能就会提示我们 The serializable class ClassName does not declare a static final serialVersionUID field of type long
。
有使用过 MyBatis-plus 框架的同学应该也发现,在使用反向代码生成时,所生成的实体类也都带有 static
final
进行修饰的 long
类型 serialVersionUID
。那么到底 serialVersionUID 是什么呢?有什么用?
附官方文档连接:https://docs.oracle.com/javase/1.5.0/docs/api/java/io/Serializable.html
它是什么?
简单概括而言, serialVersionUID
是用于在序列化和反序列化过程中进行核验的一个版本号。
序列化运行时将一个版本号(称为serialVersionUID
)与每个可序列化类相关联,该版本号在反序列化期间用于验证序列化对象的发送方和接收方是否为该对象加载了与序列化兼容的类。
如果接收方为对象加载的类与相应发送方类的serialVersionId
不同,则反序列化将导致InvalidClassException
。
可序列化类可以通过声明名为 serialVersionUID
的字段显式声明自己的 serialVersionUID
,且该字段必须是static
、final
的且类型为long
:
ANY-ACCESS-MODIFIER static final long serialVersionUID=42L;
不声明会怎样?
如Java(TM)对象序列化规范中所讲述的,如果可序列化类没有显式声明serialVersionUID
,则序列化运行时将根据类的各个方面计算该类的默认serialVersionUID
值。
但是,强烈建议所有可序列化类显式声明serialVersionUID
值,因为默认的 serialVersionUID
计算对类详细信息高度敏感,这些详细信息可能因编译器实现而异,因此在反序列化过程中可能会导致意外的InvalidClassExceptions
。
因此,为了保证在不同的java编译器实现中SerialVersionId
值是一致的,可序列化类必须声明一个显式的SerialVersionId
值。还强烈建议显式 serialVersionUID
声明尽可能使用 private
修饰符,因为此类声明仅适用于立即声明的类——serialVersionUID
字段不可用作继承成员。
其他问题
Q: 如果父类被序列化,默认情况下子类也被序列化,所以我们也需要为 child 声明 serialVersionUID
吗?
A: 建议对子类,或者说每一个存在序列化需求的类都进行 serialVersionUID
的指定,并且如上建议,采用 private
进行修饰,避免子类对父类的 protected 继承(我还没碰上炸毛的情况,所以也不好讲继承后会在什么情况下出现什么样的问题)
Q: 如果我不序列化,还需要指定吗?
A:如果不存在序列化需求,也就不存在序列化与反序列化中的比对,原则上不声明 serialVersionUID
也是可以的