抽象类中通过重写writeObject和readObject方法实现序列化控制模板,配合serialVersionUID与transient字段,在默认机制基础上插入beforeSerialize、afterDeserialize、validateOnRead等钩子逻辑,统一处理敏感过滤、版本兼容与对象校验。

在抽象类中实现通用的序列化与反序列化控制模板,核心是重写 writeObject 和 readObject 方法,并配合 serialVersionUID 与 transient 字段协同工作。关键不在于“完全接管”,而是在保留默认机制基础上,插入自定义逻辑(如敏感字段过滤、版本兼容处理、对象重建校验等)。
定义可复用的序列化钩子方法
抽象类不直接处理字节流,而是提供受保护的模版方法,供子类选择性覆盖:
-
beforeSerialize():序列化前执行,可用于清理临时状态、脱敏字段(如设为
null或空字符串) - afterDeserialize():反序列化后执行,用于重建 transient 字段、校验必填属性、初始化懒加载资源
-
validateOnRead():在
readObject中调用,抛出InvalidObjectException阻断非法反序列化
在抽象基类中统一实现 writeObject / readObject
使用 private void writeObject(ObjectOutputStream out) 和 private void readObject(ObjectInputStream in),并委托给默认逻辑 + 模版钩子:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 在
writeObject中先调用beforeSerialize(),再调用defaultWriteObject() - 在
readObject中先调用defaultReadObject(),再调用validateOnRead()和afterDeserialize() - 确保所有子类继承该抽象类后,无需重复编写序列化逻辑,只需按需重写钩子方法
处理 serialVersionUID 与版本兼容性
抽象类应显式声明 private static final long serialVersionUID = ...;,避免因编译器自动生成导致子类序列化失败:
- 若抽象类结构稳定(字段增删/类型变更少),可固定一个值,子类自动继承
- 若需支持多版本,可在
readObject中读取原始流中的类描述符(通过反射或ObjectStreamClass),结合serialVersionUID做兼容判断 - 推荐搭配
ObjectInputStream.resolveClass()或自定义ObjectInputStream子类做类映射,应对类名重构场景
规避常见陷阱
Java 序列化机制对抽象类本身无特殊限制,但需注意:
- 抽象类不能被直接实例化,但其子类对象序列化时,仍会保存抽象父类的非 transient 字段状态
- 若抽象类含
transient字段,子类反序列化后该字段为默认值(null/0/false),必须在afterDeserialize()中恢复 - 不要在
writeObject中调用out.defaultWriteObject()两次,也不要混用out.writeXXX()与默认写入,否则流格式错乱 - 避免在钩子方法中抛出未检查异常以外的异常——
writeObject只能声明IOException,readObject只能声明IOException或ClassNotFoundException
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










