文章目录
什么是serialVersionUID
序列化是将对象的状态信息转换为可存储或传输的形式的过程。
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致,这个所谓的序列化ID,就是我们在代码中定义的serialVersionUID。
serialVersionUID是用来验证版本一致性的。
所以在做兼容性升级的时候,不要改变类中serialVersionUID的值。
serialVersionUID 既然是验证版本一致性的,在做版本升级的时候(非兼容性升级),记得要修改这个字段的值哦,这样可以避免序列化混乱。
writeFile() 会在E盘生成SerializableDemo.txt文件。
正常情况下,执行readFile()会将name读取出来。
然而,如果将User类中serialVersionUID改变后,再读取readFile()会抛出一个java.io.InvalidClassException,并且指出serialVersionUID不一致。
java.io.InvalidClassException: com.nadou.User; local class incompatible: stream classdesc serialVersionUID = 2736920230361312748, local class serialVersionUID = 2736110230361312748
这是因为,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。
这也是《阿里巴巴Java开发手册》中规定,在兼容性升级中,在修改类的时候,不要修改serialVersionUID的原因。除非是完全不兼容的两个版本。所以,serialVersionUID其实是验证版本一致性的。
如果一个类实现了Serializable接口,一定要记得定义serialVersionUID,否则会发生异常。
之所以会发生异常,是因为反序列化过程中做了校验,并且如果没有明确定义的话,会根据类名及属性等自动生成一个。
可以实验下,将User类中的private static final long serialVersionUID = 2736920230361312748L; 去掉。
执行writeFile()将文件生成,然后将User类中的age属性去掉,执行readFile()读取,抛出java.io.InvalidClassException,并且指出两个serialVersionUID不同,分别是-7098663385922132191和-4368075718275022011,从这里可以看出,系统自己添加了一个serialVersionUID。
java.io.InvalidClassException: com.nadou.User; local class incompatible: stream classdesc serialVersionUID = 7098663385922132191, local class serialVersionUID = -4368075718275022011
如何idea提示生成serialVersionUID选项
示例代码:
pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
测试demo
package com.nadou;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.junit.Test;
public class SerializableDemo{
@Test
public void writeFile(){
User user = new User();
user.setName("lala");
ObjectOutputStream oos = null;
try {
oos=new ObjectOutputStream(new FileOutputStream("E:\\SerializableDemo.txt"));
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeQuietly(oos);
}
}
@Test
public void readFile(){
File file = new File("E:\\SerializableDemo.txt");
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(file));
User user = (User)ois.readObject();
System.out.println("name:"+user.getName());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
IOUtils.closeQuietly(ois);
}
}
}
class User implements Serializable {
private static final long serialVersionUID = 2736920230361312748L;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}