ObjectInputStream 恢复对象本质是将 ObjectOutputStream 写入的二进制流还原为内存对象,需满足魔数校验、类定义一致、serialVersionUID 匹配等前提,并防范 RCE 风险。

用 ObjectInputStream 恢复持久化变量状态,本质是把之前用 ObjectOutputStream 写入文件的对象字节流还原为内存中的 Java 对象。这不等于“自动续命”,而是一次有前提、有约束、需设防的操作。
确保对象文件真正可反序列化
ObjectInputStream 只认 ObjectOutputStream 写出的二进制流。它会校验文件头魔数 AC ED 00 05,不是这个开头,直接抛 StreamCorruptedException。
- 确认该文件确实由
ObjectOutputStream.writeObject()写入,且写完调用了close()或flush() - 不能拿 JSON、XML、纯文本文件去试;也不能用记事本编辑过序列化文件——哪怕改一个字节都会破坏结构
- 建议在序列化时同步记录类名和
serialVersionUID值,便于后续排查版本匹配问题
类定义必须稳定且可信任
反序列化不是魔法,它依赖运行时类的结构与序列化时一致。一旦脱节,就会在 readObject() 调用瞬间失败。
- 被恢复的类及其所有非
transient字段类型,都必须实现Serializable - 显式声明
private static final long serialVersionUID = 1L;(避免 IDE 自动生成差异) - 父类若不可序列化,子类必须提供无参构造器,否则反序列化时无法实例化
- 禁止反序列化来自不可信来源的数据(如网络接收、用户上传),可能触发远程代码执行(RCE)
用 try-with-resources 正确打开并捕获三类关键异常
裸写 new ObjectInputStream(...) 是高危操作。必须包裹资源管理,并区分处理不同失败场景。
- IOException:文件不存在、权限不足、磁盘满、流损坏等 I/O 层问题
- ClassNotFoundException:当前 classpath 缺失该类(比如 jar 包未部署、类被重命名或删掉)
-
InvalidClassException:
serialVersionUID不匹配,或字段被删/改类型/改访问修饰符
示例写法:
try (FileInputStream fis = new FileInputStream("config.state");
ObjectInputStream ois = new ObjectInputStream(fis)) {
Config config = (Config) ois.readObject();
// 使用 config...
} catch (IOException e) {
log.error("配置文件读取失败", e);
} catch (ClassNotFoundException e) {
log.error("Config 类未找到,请检查依赖", e);
} catch (InvalidClassException e) {
log.error("配置文件版本过旧,无法兼容当前 Config 类", e);
}
注意变量状态的实际恢复边界
反序列化只恢复对象图中可序列化的实例字段,其他内容一律丢弃或重置。
-
static字段不会恢复,值仍为类加载时的默认值或静态初始化结果 -
transient字段跳过序列化,反序列化后为null、0、false等默认值 - 枚举、Lambda、匿名内部类等特殊对象支持有限,部分情况会抛
InvalidObjectException - 若类含自定义
readObject()方法,需确保其逻辑健壮,否则异常会向上透出


















