在咱们的项目开发过程当中,每每会有这样的要求,对于须要序列化的类,在实现serializable接口的同时,要求在类中定义serialVersionUID.java
public static final long serialVersionUID = -11222222122xxxxL;
复制代码
这时咱们每每会产生疑问,这个serialVersionUID是干什么用的呢?在讨论serialVersionUID时,咱们必须结合Java的序列化对其进行分析.bash
众所周知,Java的序列化机制的主要做用在于两点:网络
那么在使用序列化机制保存对象的时候,咱们就须要考虑一个问题:随着应用程序的演进,序列化对象自己的定义也在发生更改,那么旧版本的程序是否还能向后兼容新的序列化对象?或者,新版程序还可否向前兼容去处理老版本的对象?spa
在类中定义serialVersionUID静态域就是为了Java序列化的版本兼容,为何这么说呢? 首先,让咱们回顾一下Java序列化的知识:版本控制
当序列化存储一个对象时,这个对象所属的类也必须存储.这个类的描述包含了:code
到这里,咱们知道serialVersionUID就是序列化对象的指纹,而它的值是经过对类,超类,接口,域类型和方法签名按照规范方式排序,而后进行SHA获得的20字节长度的数据. 所以,理论上来讲当对象所属的类的定义发生变化时,其serialVersionUID必定会发生变化,可是因为序列化机制只使用SHA码的前8个字节,所以不是必定发生变化,可是概率仍是很是大的.对象
而序列化机制在读入一个对象时,会使用它的指纹与它所属的类的当前指纹进行比对,若是它们不匹配,就说明这个类的定义在该对象被写出以后发生过变化,从而会抛出java.io.InvalidClassException异常.排序
照这样来讲,岂不是无法进行版本兼容了?固然不会.接口
Java核心技术中是这样解释的:内存
若是一个类具备名为serialVersionUID的静态数据成员,它就再也不须要人工地计算其指纹,只需直接使用这个值
一旦这个静态数据成员被置于某个类的内部,那么序列化系统就能够读入这个类的对象的不一样版本
到这里,添加serialVersionUID静态域的做用已经很清楚了.经过这一措施,可使Java的序列化更好地进行版本控制,避免抛出java.io.InvalidClassException异常,虽然当出现数据的版本不一致时,可能会致使数据的一部分丢失,但至少保证了服务的可用.
当序列化对象与类的版本不一致时,Java序列化是如何工做的?
若是这个类只有方法发生了变化,那么在读入新对象数据时是不会有任何问题的.可是若是字段域发生了变化,那么可能出现问题,例如可能类中的字段减小或者类型的改变等等.