Java序列化中,readObject可作为反序列化钩子,在对象还原后初始化字段;需严格定义签名、调用defaultReadObject(),之后重建transient字段或派生字段;配合writeObject可实现自定义序列化;readResolve则用于替换最终返回对象以保障单例等语义。

Java 序列化机制中,可通过 readObject 方法作为反序列化钩子,在对象被反序列化后、返回给调用者之前,动态初始化字段。
定义 private void readObject(ObjectInputStream in) 钩子方法
在可序列化类中声明一个私有的、无返回值、参数为 ObjectInputStream 的 readObject 方法,JVM 会在反序列化该类实例时自动调用它(前提是该类未使用 serialPersistentFields 自定义字段列表)。
- 必须严格匹配签名:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException - 需先调用
in.defaultReadObject(),否则非 transient 字段不会被正常恢复 - 调用
defaultReadObject()后,对象字段已从流中读取完毕,此时可安全执行初始化逻辑(如设置默认值、重建 transient 字段、校验状态等)
利用 readObject 初始化 transient 字段或派生字段
transient 字段不会被自动序列化,反序列化后为默认值(null、0、false)。可在 readObject 中按需重建:
- 例如:缓存字段、线程局部变量、数据库连接池引用等,应在钩子中重新创建或重置
- 也可基于已反序列化的字段计算并设置派生字段,如
fullName基于firstName和lastName拼接 - 注意避免在钩子中触发可能失败的外部操作(如网络请求),否则会中断整个反序列化流程
配合 writeObject 实现自定义序列化逻辑
若需控制哪些字段写入流(比如跳过敏感数据或压缩结构),应同时提供 writeObject 方法,并在其中显式写出必要字段。此时 readObject 必须按相同顺序和类型读取:
立即学习“Java免费学习笔记(深入)”;
- 调用
in.defaultReadObject()不再适用,改用in.readXXX()手动读取 - 确保读写顺序一致,否则抛出
StreamCorruptedException - 适合精细控制序列化格式,但维护成本更高,一般仅在兼容性或安全性有强需求时采用
替代方案:使用 readResolve 控制最终返回的对象
若需替换反序列化生成的对象(如实现单例、规范枚举语义),可定义 readResolve 方法:
- 签名:
private Object readResolve() throws ObjectStreamException - 它在
readObject执行完毕后、对象返回前被调用 - 返回的对象将作为反序列化的最终结果,原对象可被 GC 回收
- 常用于防止反序列化破坏单例契约,或统一对象构造逻辑


















