Java中通过private的readObject和writeObject方法可精细控制序列化与反序列化,需调用defaultReadObject/defaultWriteObject并保持读写顺序一致,适用于加密、版本兼容等场景。

在 Java 中,通过 readObject 和 writeObject 方法可以精细控制对象的序列化与反序列化行为,适用于需要跳过某些字段、加密敏感数据、兼容版本变更或执行初始化逻辑等场景。这两个方法必须声明为 private,且签名严格固定,JVM 会在序列化/反序列化时自动调用它们(前提是类实现了 Serializable)。
自定义 writeObject:控制序列化过程
当对象被序列化时,JVM 会优先查找当前类中是否定义了 private void writeObject(ObjectOutputStream out) throws IOException。若存在,就跳过默认序列化逻辑,转而执行你写的代码。
- 必须先调用
out.defaultWriteObject()(除非你完全手动处理所有字段),否则非 transient 字段不会被写入 - 可在其前后添加自定义逻辑,比如加密 password 字段、记录序列化时间、写入额外元数据
- 注意:不能直接调用
out.writeObject(this),会引发无限递归
示例:
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // 序列化其他字段
out.writeUTF(encrypt(password)); // 单独加密写入
}
自定义 readObject:控制反序列化过程
反序列化时,JVM 查找 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException。它负责从流中读取数据并恢复对象状态。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 同样建议先调用
in.defaultReadObject()恢复默认字段(尤其是非 transient 成员) - 之后按写入顺序读取自定义内容,比如解密 password、校验数据完整性、重建 transient 字段(如缓存、连接等)
- 注意字段读取顺序必须与
writeObject中的写入顺序严格一致
示例:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // 恢复普通字段
this.password = decrypt(in.readUTF()); // 解密还原
}
注意事项和常见陷阱
- 两个方法必须是
private,且不能是static或final;否则 JVM 忽略它们,走默认逻辑 - 如果父类也需要自定义,父类也得提供对应方法,并在子类方法中显式委托(如
super.readObject(in)不生效,需手动调用父类逻辑) - 反序列化构造对象时不走任何构造器(包括无参构造),所以
readObject是初始化 transient 字段或修复对象状态的唯一可靠时机 - 涉及安全敏感操作(如反序列化校验)时,务必在
readObject中做输入检查,防止恶意数据触发漏洞
替代方案:Externalizable 接口
若需要完全接管序列化(连字段名、类型都不保留),可实现 Externalizable 接口,重写 writeExternal 和 readExternal。但它要求必须有 public 无参构造器,且不自动处理继承关系,适用性更窄,一般推荐优先用 readObject/writeObject + Serializable。

















