java反序列化需类实现serializable接口并存在对应字节码;用objectinputstream包装bytearrayinputstream调用readobject()还原对象,须注意serialversionuid匹配、类型一致及安全风险。

Java 中反序列化将字节数组还原为对象,核心是使用 ObjectInputStream 配合 ByteArrayInputStream,但前提是该对象类实现了 Serializable 接口,且反序列化环境中有对应类的字节码(即类定义必须存在且版本兼容)。
确保类可序列化
被序列化的类必须实现 Serializable 接口,这是 Java 提供的标记接口,不需实现任何方法:
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
// 构造器、getter/setter 省略
}
建议显式声明 serialVersionUID,避免因编译器自动生成差异导致 InvalidClassException。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
用 ObjectInputStream 还原对象
将字节数组包装为 ByteArrayInputStream,再套一层 ObjectInputStream,调用 readObject() 即可:
byte[] data = ...; // 来自文件、网络或之前序列化的结果
try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bis)) {
User user = (User) ois.readObject(); // 向下转型,注意类型匹配
}
- 必须按写入顺序读取,且类型要严格一致(如写的是
User,就不能读成Person) - 若字节数组为空或损坏,会抛出
StreamCorruptedException或ClassNotFoundException - 反序列化过程会调用类的无参构造器(仅用于重建对象,不执行初始化逻辑),然后直接填充字段值
注意安全风险与替代方案
原生 Java 反序列化(ObjectInputStream)存在严重安全漏洞,攻击者可构造恶意字节数组触发任意代码执行。生产环境禁止反序列化不可信来源的数据。
- 如必须使用,可配合
ObjectInputStream.resolveClass()重写,白名单限制允许反序列化的类 - 更推荐使用 JSON(如 Jackson、Gson)、XML 或 Protocol Buffers 等语言中立、可读性强、安全性更高的序列化格式
- 若坚持用二进制,可考虑
Kryo或FST,它们性能更好,也支持注册类白名单
常见失败原因
还原失败通常不是代码写错,而是环境或数据问题:
- 类未在当前 ClassLoader 中找到 → 检查 jar 包是否缺失、类名是否拼写错误
-
serialVersionUID不匹配 → 编译后修改了字段但没更新 UID,抛出InvalidClassException - 字节数组被截断或编码转换污染(如误用 UTF-8 解码二进制流)→ 确保字节数组原始完整,不要经过字符串编解码
- 含不可序列化字段(如
Thread、Socket)且未标记transient→ 序列化阶段就已失败,不会走到反序列化
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










