JDK 序列化, 碰到serialVersionUID 不一致问题,怎么处理?

本文探讨了在Java对象序列化过程中遇到的serialVersionUID不一致问题及其处理方法。当对象的属性发生变化时,自动生成的serialVersionUID会变,导致反序列化失败。解决这个问题可以通过手动设置serialVersionUID并自定义序列化和反序列化策略,确保新旧版本对象的兼容。同时,文章提醒程序员不应安于现状,应不断学习以避免职业危机。
摘要由CSDN通过智能技术生成

JDK 序列化, 碰到serialVersionUID 不一致问题,怎么处理?

公司有个子服务较多,交互频繁的系统,有一些需要共享传输的对象,它们通过 JDK 序列化(Java Object Serialization)后进行交互;但是由于一些不可描述的历史原因,这些对象存在多个版本,每个版本中的属性不一致,且未设置 serialVersionUID

这阵子在做梳理/统一代码的工作,打算统一这些对象的版本和固定serialVersionUID,但是由于服务较多,上线发版时会有一段新老版本共存的时期,所以得考虑这些对象序列化的兼容问题,新的对象反序列化一定得兼容老的对象

Java Object Serialization

Java对象序列化(Serialization)是指将Java中的对象转为字节流,从而可以方便的存储或在网络中传输,反序列化(Deserialization)是指将字节流转位Java对象

一般情况下,Java Object Serialization指的是利用JDK自带的功能对对象进行序列化/反序列化,而不是使用其他的序列化库进行(反)序列化

JDK 序列化中,要求对象必须实现java.io.Serializable接口,基本使用方式如下:

Serialization
// Serialize today's date to a file.
FileOutputStream f = new FileOutputStream("tmp");
ObjectOutput s = new ObjectOutputStream(f);
s.writeObject("Today");
s.writeObject(new Date());
s.flush();

Deserialization

// Deserialize a string and date from a file.
FileInputStream in = new FileInputStream("tmp");
ObjectInputStream s = new ObjectInputStream(in);
String today = (String)s.readObject();
Date date = (Date)s.readObject();

serialVersionUID

private static final long serialVersionUID = 1L;

Java Object Serialization 会使用对象中的 serialVersionUID 常量属性作为该对象的版本号,进行反序列化时会校验该版本号是否一致,如果不一致会导致序列化失败,抛出InvalidClassException异常

默认情况下,JVM 为每一个实现了 Serializable 的接口的类生成一个serialVersionUID(long),这个 ID 的计算规则是通过当前类信息(类名、属性等)去生成的,所以当属性有变更时这个serialVersionUID 也一定会发生变更

这个 serialVersionUID 的生成,和所使用的JDK有关,不同的JDK可能会生成不一样的版本号,所以最好是手动生成一个,大多数 JAVA IDE 都会提供这个生成的功能

而且考虑到实际业务场景,变更属性是常有的事,如果使用自动生成的版本号很容易造成 serialVersionUID 不一致的问题,导致反序列化失败

serialVersionUID 不一致时的兼容处理

处理这个不一致也很简单,既然反序列化时使用 ObjectInputStream来实现,那么这里自定义一个 CompatibleInputStream 继承ObjectInputStream,然后重写 readClassDescriptor 方法即可

当遇到目标数据 Class 版本号和本地 Class 版本号不一致时,默认使用本地版本的 Class

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值