抽象类中通过重写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),并委托给默认逻辑 + 模版钩子:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 在
writeObject中先调用beforeSerialize(),再调用defaultWriteObject() - 在
readObject中先调用defaultReadObject(),再调用validateOnRead()和afterDeserialize() - 确保所有子类继承该抽象类后,无需重复编写序列化逻辑,只需按需重写钩子方法
处理 serialVersionUID 与版本兼容性
抽象类应显式声明 private static final long serialVersionUID = ...;,避免因编译器自动生成导致子类序列化失败:
立即学习“Java免费学习笔记(深入)”;
- 若抽象类结构稳定(字段增删/类型变更少),可固定一个值,子类自动继承
- 若需支持多版本,可在
readObject中读取原始流中的类描述符(通过反射或ObjectStreamClass),结合serialVersionUID做兼容判断 - 推荐搭配
ObjectInputStream.resolveClass()或自定义ObjectInputStream子类做类映射,应对类名重构场景
规避常见陷阱
Java 序列化机制对抽象类本身无特殊限制,但需注意:
- 抽象类不能被直接实例化,但其子类对象序列化时,仍会保存抽象父类的非 transient 字段状态
- 若抽象类含
transient字段,子类反序列化后该字段为默认值(null/0/false),必须在afterDeserialize()中恢复 - 不要在
writeObject中调用out.defaultWriteObject()两次,也不要混用out.writeXXX()与默认写入,否则流格式错乱 - 避免在钩子方法中抛出未检查异常以外的异常——
writeObject只能声明IOException,readObject只能声明IOException或ClassNotFoundException

















