Java中自定义readObject方法可精确控制反序列化,需为private void且调用in.defaultReadObject()恢复字段,再校验或修正;须与writeObject一致,并注意安全风险。

在 Java 中,自定义 readObject 方法可以精确控制对象反序列化过程,比如校验数据、恢复瞬态状态、兼容旧版本字段,或防止反序列化攻击。
实现 private void readObject(ObjectInputStream in)
该方法必须是 private、void 返回、参数为 ObjectInputStream,且定义在可序列化的类中(即实现了 Serializable)。JVM 在反序列化时会自动调用它,**替代默认的字段还原逻辑**。
- 必须先调用
in.defaultReadObject()(除非你完全手动读取所有字段)——它负责还原非瞬态(transient)、非静态字段的值; - 之后可读取额外数据(如版本号、加密校验码),或对已还原字段做校验/修正;
- 若类有
serialVersionUID,建议显式声明,避免因字段变更导致InvalidClassException。
典型使用场景与写法示例
比如一个带密码哈希和创建时间的用户类,需确保反序列化后时间不为空、密码哈希格式合法:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // 恢复 name、passwordHash、createdAt 等非 transient 字段
// 校验:createdAt 不应为 null
if (createdAt == null) {
throw new InvalidObjectException("createdAt must not be null");
}
// 兼容旧版本:若 passwordHash 是空字符串,设为默认占位符
if (passwordHash != null && passwordHash.trim().isEmpty()) {
passwordHash = "NO_PASSWORD_SET";
}
}
配合 writeObject 保持一致性
如果重写了 readObject,通常也要重写 private void writeObject(ObjectOutputStream out),确保写入的数据能被正确读回:
立即学习“Java免费学习笔记(深入)”;
- 在
writeObject中调用out.defaultWriteObject()写基础字段; - 如有额外逻辑(如写入签名、版本标记),需在
readObject中按相同顺序读取; - 二者读写顺序和内容必须严格一致,否则反序列化会失败或数据错乱。
安全注意事项
自定义反序列化是高风险操作,容易引入反序列化漏洞:
- 避免在
readObject中执行任意代码(如反射调用、资源加载、网络请求); - 不要信任输入流中的数据,所有字段值都应校验(如长度、范围、正则格式);
- 敏感字段(如密钥)应声明为
transient,并在readObject中按需重建(例如从系统属性或环境变量读取); - 考虑使用更安全的替代方案,如 JSON + Jackson/Gson,或启用 JDK 的反序列化过滤器(
jdk.serialFilter)。


















