Java中对象序列化要求实体类必须实现Serializable接口,否则抛出NotSerializableException;需显式声明serialVersionUID,确保成员变量可序列化,并注意继承、内部类及第三方类的处理。

Java中使用ObjectOutputStream写入对象时,如果实体类没有实现Serializable接口,会抛出java.io.NotSerializableException。这是Java序列化机制的强制要求——只有标记为可序列化的类才能被ObjectOutputStream持久化到字节流中。
让实体类实现 Serializable 接口
最直接、标准的解决方式是让目标类显式实现Serializable接口。该接口是空接口(marker interface),不定义任何方法,仅用于告知JVM该类支持序列化。
- 在类声明处添加
implements Serializable - 建议显式声明
serialVersionUID字段,避免因编译器自动生成差异导致反序列化失败。例如:
private static final long serialVersionUID = 1L; - 确保类中所有非静态、非瞬态(non-transient)的成员变量所属类型也实现了
Serializable;否则会报相同异常
处理不可修改的第三方类
若实体类来自第三方库且无法修改源码(如java.util.Date本身可序列化,但某些自定义工具类可能不可),可采用以下方式绕过:
- 创建一个可序列化的包装类(Wrapper),将原对象作为字段封装,并在
writeObject/readObject中手动控制序列化逻辑 - 使用
transient关键字标记无法序列化的字段,再通过自定义writeObject和readObject方法保存/恢复其状态 - 改用JSON(如Jackson/Gson)或Protobuf等替代序列化方案,它们不要求实现
Serializable
检查继承链与内部类
序列化时容易忽略的细节:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
- 父类未实现
Serializable?子类虽实现了,但父类字段不会被自动序列化;若父类无默认构造函数,反序列化可能失败 - 匿名内部类、局部内部类默认持有外部类引用,若外部类不可序列化,也会触发异常;建议改用静态内部类或独立类
- Lambda表达式和方法引用本质上是生成的私有内部类,通常不可序列化,除非明确标注且上下文满足条件
临时规避(不推荐生产环境)
仅用于调试或测试场景,不建议在正式代码中使用:
- 重写
ObjectOutputStream的annotateClass方法(需继承并替换),但这破坏了JVM安全模型,且高版本JDK可能限制此类操作 - 用
Unsafe或字节码增强强行注入接口——风险极高,兼容性差,易引发运行时问题
核心原则是:序列化不是“开关”,而是契约。只要用ObjectOutputStream,就必须遵守Serializable规范。合理设计类结构、明确序列化意图、优先选用更现代的序列化方式,才是长久之策。

















