反序列化问题
Java对象的序列化需要实现接口 Serializable ,其中有一个序列化版本id serialVersionUID,序列化和反序列化的版本号需要一致,否则会报对象版本号不一致的错误。
关于idea如何自动生成序列化id请点击 Idea自动生成序列化版本id serialVersionUID
举例说明
这里举一个例子说明版本号不一致反序列化异常的情况,步骤如下:
1. 首先使用版本号 private static final long serialVersionUID = 1L 序列化对象到磁盘文件;
2. 然后使用版本号 private static final long serialVersionUID = 2L 反序列化磁盘文件解析对象到内存;
import java.io.*;
/**
*Java对象转json字符串
*/
public class HelloWorld {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//序列化 注释反序列化 序列化版本id serialVersionUID=1L
Employee e = new Employee("张三","男", 22);
FileOutputStream fileOut = new FileOutputStream("d:/emp.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
//反序列化 注释序列化 序列化版本id serialVersionUID=2L
// FileInputStream fileIn = new FileInputStream("d:/emp.txt");
// ObjectInputStream in = new ObjectInputStream(fileIn);
// Employee e = (Employee) in.readObject();
// in.close();
// fileIn.close();
//
// System.out.println(e.getName());
}
}
//JavaBean.java
class Employee implements Serializable {
//序列化id版本号
private static final long serialVersionUID = 1L;
private String name;
private String sex;
private Integer age;
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
public Employee(String name, String sex, Integer age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
输出:
经过上面的一顿操作报了一个Exception in thread "main" java.io.InvalidClassException: Employee; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
异常,因为前后的版本号不一样。所以,在定义Java的类时,如果实现了Serializable接口,一定要给类定义一个序列化id的版本号serialVersionUID,且在系统升级过程中该值不要再改变,这样可以有效避免反序列化带来的问题。
为什么要定义serialVersionUID
为什么一定要定义一个呢?
如果不定义序列化id serialVersionUID ,JVM虚拟机会默认给一个serialVersionUID 值,当我们的类变更的时候,比如添加或修改属性,这个serialVersionUID值是会变的。
还是上面的例子,使用下面的步骤,不定义serialVersionUID 值,前后修改类的属性,同样会报反序列化异常
1. 使用上面的Employee类序列化到磁盘文本文件。
2. 修改Employee类,增加一个private String testProp;属性
3. 使用修改后的类反序列化。
我们发现执行上面的操作后,前后两次的serialVersionUID 值不一致。