java序列化版本号

Hits: 654

在写java程序的时候经常会看到类中会有一个序列化版本号:serialVersionUID。这个值有的类是1L,有的又是很长的数值,通常是这样声明的:

或者:

这是为什么呢?今天来总结下这个序列化版本号的作用。
先说说序列化,java的序列化指的是把java对象转化为字节序列(bytes)的过程,而反序列化就是把字节序列转化为java对象的过程。这个功能主要的作用是把java对象存储在磁盘上或者在网络上传输,如果没有这个功能你想要传输对象的话只能通过字符串拼接了。至于具体是怎么实现的查下api就知道,很简单,不再赘述了。正是因为有了反序列化机制,所以jvm需要判断需要转化的两个类是不是同一个类,于是就需要一个序列化版本号。如果在反序列化的时候两个类的serialVersionUID不一样则jvm会抛出InvalidCastException的异常;如果serialVersionUID一致则表明可以转换。
下面再来讨论下这个字段的值。
首先这个值是可以不指定的,这样的话JVM在编译时会指定一个默认值,根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段。这样咋一看是没什么问题的,但是这种方式不支持反序列化重构。所谓重构就是可以对类增加或者减少属性字段,也就是说即使两个类并不完全一致,他们也是可以转换的,只不过如果找不到对应的字段,它的值会被设为默认值。如果反序列化时进行了重构,会导致两个不同的类生成的serialVersionUID不一致,那就不能进行反序列化了。

还有一个常见的值是1L(或者其他固定值),如果所有类都这么写那还怎么区分它们,这个字段还有什么意义吗?有的!首先如果两个类有了相同的反序列化版本号,比如1L,那么表明这两个类是支持在反序列化时重构的。但是会有一个明显的问题:如果两个类是完全不同的,但是他们的序列化版本号都是1L,那么对于JVM来说他们也是可以进行反序列化重构的!这这显然是不对的,但是回过头来说这种明显的,愚蠢的错误在实际开发中是不太可能会犯的,如果不是那么严谨的话用1L是个不错的选择。

一般的情况下这个值是显式地指定为一个64位的哈希字段,比如你写了一个类实现了java.io.Serializable这个接口,在eclipse里会提示你加上这个序列化id。这样做可以区分不同的类,也支持反序列化重构。

总结下:

serialVersionUID 区分不同类 支持相同类的重构
不指定 YES NO
1L NO YES
64位哈希值 YES YES

简单而言,从严谨性的角度来说,指定64位哈希值>默认值1L>不指定这个值,具体怎么使用就看你的需求啦。


发表评论

电子邮件地址不会被公开。 必填项已用*标注