项目中关于serialVersionUID的隐藏bug

说明:这篇文章关于IO流,序列化serialVersionUID的功能知识没有介绍,若没有相关基础,遇到不懂请自行Google。

问题

这几天在复习序列化时,发现了我项目中存在的一个隐藏bug。
我项目中的entity都继承于一个基类BaseEntity,这个类大概是这样的:

class BaseEntity implements Serializable{
    public static final long serialVersionUID = 1L;
	//属性...
}

因此,我在没有测试的情况下,误以为子类继承了这个BaseEntity,那么子列就不用再添加这个serialVersionUID了。
其实,这是不对的,虽然子类继承了这个serialVersionUID,但是,jvm还是会为子类这个对象重新赋值一个serialVersionUID,除非你在子类重新显式声明一个serialVersionUID。

测试过程:

测试代码:
注意:注释的代码之后会用到

public class PrivateTest extends Base{
//    private static final long serialVersionUID = 1L;
    private int id;
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

//    private boolean gender;
//
//    public boolean isGender() {
//        return gender;
//    }
//
//    public void setGender(boolean gender) {
//        this.gender = gender;
//    }
    @Override
    public String toString() {
        return "PrivateTest{" +
                "id=" + id +
                ", name='" + name + '\'' +
//                ", gender='" + gender + '\'' +
                '}';
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        File file = new File("./text.txt");
        myWrite(file);
//        myRead(file);
    }

    private static void myRead(File file) throws IOException, ClassNotFoundException {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
        PrivateTest o = (PrivateTest)in.readObject();
        System.out.println(o.toString());
        in.close();
    }

    private static void myWrite(File file) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
        PrivateTest test = new PrivateTest();
        test.setId(1);
        test.setName("abc");
        out.writeObject(test);
        out.close();
    }
}
class Base implements Serializable{
    public static final long serialVersionUID = 1L;
}

一开始,我们运行上面的代码的myWrite方法,往文件写入一个对象,接着,我们把gender属性的几行注释代码恢复,运行myRead方法,会发现读取报错InvalidClassException。
报错如下:

Exception in thread "main" java.io.InvalidClassException: 
privatetest.PrivateTest; local class incompatible: 
stream classdesc serialVersionUID = -9051711779420750007, 
local class serialVersionUID = 7378139454451283922

发现本地和流中的serialVersionUID不同,说明我们的privateTest对象自身没有serialVersionUID,也就是父类的serialVersionUID没有发挥作用。

那么,接下来我们在PrivateTest类中添加上serialVersionUID之后,再重复上面的操作:先运行myWrite方法,写入对象,然后取消对gender属性的注释,运行myRead方法,会发现可以成功打印出对象信息,说明修改成功。

成功打印对象信息:

PrivateTest{id=1, name='abc', gender='false'}

总结

总结一下,子类继承父类时,若父类实习Serializable接口,同时有serialVersionUID,子类也需要声明serialVersionUID,否则序列化读取写入对象时,可能会报错InvalidClassException。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值