栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

关于java反序列化失败的问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

关于java反序列化失败的问题

最近刚好在打java基础,但是用ObjectOutputStream进行反序列的时候
遇到了反序列化失败的问题,所以在这里讨论一下反序列化失败的问题

目录
  • 1. 反序列化失败抛出的异常信息
  • 2. 在java中类的区分
    • 1.serializable接口
    • 2.java中类的区分
  • 3. 序列化版本号
    • 1.序列化版本号的作用
    • 2.手动创建序列化版本号
  • 4. 解决反序列化失败的方法

1. 反序列化失败抛出的异常信息

java.io.InvalidClassException: javaSE.bean.Student; local class incompatible: stream classdesc serialVersionUID = -4563547663326088190, local class serialVersionUID = -27206582129922100
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2001)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1848)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2158)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1665)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:501)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:459)

异常信息:

  • local class incompatible
  • 本地的类不匹配
  • stream classdesc serialVersionUID = -4563547663326088190
  • 在流中类的序列化版本号是-4563547663326088190
  • local class serialVersionUID = -27206582129922100
  • 本地类的序列化版本号是-27206582129922100

很明显抛出异常的原因就是:
本地类的序列化版本号和我们进行序列化时的序列化版本号不同
所以要搞清楚这个异常就要搞清楚序列化版本号是个什么东西


2. 在java中类的区分 1.serializable接口

我们在进行序列化的时候会让某个类去实现serializable接口
比如我有一个student类去实现serializable接口:

public class Student implements Serializable {
    private int age;
    private String name;
    
    public Strudent(int age, String name){
    this.age = age;
    this.name = name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + ''' +
                '}';
    }
}
  • serializable接口是一个标志接口,在类中我们并没有实现任何方法
  • 实现serializable接口是因为jvm会自动分配一个序列化版本号
2.java中类的区分
  • 第一,以类名来区分。类名不一样,肯定不是同一个类。
  • 第二, 如果类名一样,靠序列化版本号区分。

3. 序列化版本号

读到这里你肯定对序列化版本号多少有点了解了,下面是对序列化版本号的具体说明

1.序列化版本号的作用

在讲清楚序列化版本号之前,我们来看个故事:


三年前小蓝在开发某个项目的时候写了一个学生类:

public class Student implements Serializable {
    private int age;
    private String name;
    
    public Strudent(int age, String name){
    this.age = age;
    this.name = name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + ''' +
                '}';
    }
}

三年后,小蓝跑路了。来了个新人小红,由于业务需求,小红在小蓝写的类上增加了一个id属性

public class Student implements Serializable {
    private int age;
    private String name;
    private int id;

    public Student(int age, String name, int id) {
        this.age = age;
        this.name = name;
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + ''' +
                ", id=" + id +
                '}';
    }
}

当小红改完代码,重新运行程序时,项目跑不了,抛出的异常让小红懵逼了

java.io.InvalidClassException: javaSE.bean.Student; local class incompatible: stream classdesc serialVersionUID = -4563547663326088190, local class serialVersionUID = -27206582129922100
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2001)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1848)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2158)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1665)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:501)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:459)


小红请教了她的师傅,师傅告诉她:加一个序列化版本号就行了
小红照做了:

public class Student implements Serializable {
    private static final long serialVersionUID = 7471391170055841173L;
    private int age;
    private String name;
    private int id;

    public Student(int age, String name, int id) {
        this.age = age;
        this.name = name;
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + ''' +
                ", id=" + id +
                '}';
    }
}


小红运行了代码,成功地跑了起来,小红这才放心地下班了

  • 可以看到一个继承了 serializable 接口的类如果不加上一个 serialVersionUID
    用 ObjectInputStream 进行序列化之后,如果这个类有一点改变,反序列化就会失败
  • 序列化版本号的作用就是告诉 java 虚拟机 改变之前的类和改变之后的类是同一个类
  • 比如上面的例子:小蓝三年前写的 Student 和小红改的 Student 类是同一个类,但是却反序列化失败了
    因为 Student 类继承了 serializable 接口,会自动分配一个 serialVersionUID。
    但是因为小红把代码改了,在重新编译运行的时候,又会分配一个serialVersionUID
    导致之前序列化时类的 serialVersionUID 和反序列化时类 serialVersionUID 所以就抛出了异常
2.手动创建序列化版本号

对于序列化版本号的并没有多大讲究,
在实现了serializable接口的类中添加一个serialVersionUID即可
只要保证在一个项目中序列化版本号不要重复就行

  • 比如:
private static final long serialVersionUID = 1L;
  • 又或者:
private static final long serialVersionUID = 7471391170055841173L;
  • idea中可以选中类名按Alt + Enter即可自动生成serialVersionUID

4. 解决反序列化失败的方法
  • 如果出现以下异常信息:

  • 要把stream classdesc serialVersionUID复制到你序列化的那个类中
  • 别忘了加private static final long
  • 数字后面还要加一个L,表示long类型
  • 比如

  • 为了避免反序列化失败情况的发生,一个类实现了serializable接口就一定要添加一个serialVersionUID

  • 比如:


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1031251.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号