反序列化问题

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;
    }
}

输出:

Java反序列化的问题

经过上面的一顿操作报了一个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. 使用修改后的类反序列化。

Employee; local class incompatible: stream classdesc serialVersionUID = 3023832937750443642, local class serialVersionUID = 5753936127789611998

 我们发现执行上面的操作后,前后两次的serialVersionUID 值不一致。