阿里的开发手册中有下面这条强制性的规定,默认在序列化类中必须含有serialVersionUID,请不要修改 serialVersionUID 字段,避免反序列失败;看到这里可能脑海里就会出现一系列的问题。
- 序列化和反序列化是什么?
- 实现序列化和反序列化为什么要实现 Serializable 接口?
- 实现 Serializable 接口就算了, 为什么还要显示指定 serialVersionUID 的值?
- 我要为 serialVersionUID 指定个什么值?
一、序列化和反序列化
- 序列化:把对象转换成字节序列的过程称之为对象的序列化。
- 反序列化:把字节序列恢复为对象的过程称之为反序列化。
二、什么时候需要用到序列化和反序列化呢?
当我们只在本地JVM中运行Java实例,这个时候我们是不需要进行序列化与反序列化的,但是当我们需要将内存中的对象持久化到磁盘或者数据库中的时候,当我们需要与浏览器进行交互的时候,当我们需要实现RPC(远程调用),这个时候我们就需要进行序列化与反序列化。
三、为什么要实现 Serializable 接口?
在 Java 中实现了 Serializable 接口后, JVM 会在底层帮我们实现序列化和反序列化, 如果我们不实现 Serializable 接口, 那自己去实现一套序列化和反序列化。
四、为什么还要指定serialVersionUID的值?
如果不显示的指定serialVertionUID,JVM在序列化时会根据属性自动生成一个serialVersionUID,然后与属性一起序列化,再进行持久化或网络传输。在反序列化时,JVM 会再根据属性自动生成一个新版 serialVersionUID,然后将这个新版 serialVersionUID 与序列化时生成的旧版 serialVersionUID 进行比较,如果相同则反序列化成功, 否则报错。
在实际开发中, 不显示指定 serialVersionUID 的情况会导致什么问题?如果我们的类写完后不再修改,那当然不会有问题。但这在实际开发中是不可能的,我们的类会不断迭代,一旦类被修改了,那旧对象反序列化就会报错。所以在实际开发中, 我们都会显示指定一个 serialVersionUID,值是多少无所谓, 只要不变就行。
具体示例;
先后执行测试类中的序列化代码 , 然后 User 类新增一个属性 sex , 执行反序列化的代码结果如下:
报错结果为序列化与反序列化产生的 serialVersionUID 不一致.
如果我们显示的指定serialVersionUID (private static final long serialVersionUID = 1L;) ,那么就不会问题。
结果如下:
五、Java 序列化的其他特性
被 transient 关键字修饰的属性不会被序列化, static 属性也不会被序列化。
先后进行序列化与反序列化的代码测试结果如下:
static 属性为什么不会被序列化?
因为序列化是针对对象而言的,而 static 属性优先于对象存在, 随着类的加载而加载, 所以不会被序列化.
看到这个结论, 是不是有人会问, serialVersionUID 也被 static 修饰, 为什么 serialVersionUID 会被序列化?
其实 serialVersionUID 属性并没有被序列化, JVM 在序列化对象时会自动生成一个 serialVersionUID, 然后将我们显示指定的 serialVersionUID 属性值赋给自动生成的 serialVersionUID。