java序列化时,不可序列化成员变量需加transient修饰符跳过序列化,反序列化后为null或默认值;自定义类及其嵌套对象均须实现serializable;内部类建议用static避免隐式引用;可重写readobject恢复transient字段;分布式场景应避免异常对象序列化,推荐结构化错误码或json。

Java 序列化时,如果一个实现了 Serializable 的类里含有不可序列化的成员变量(比如 Thread、Socket、Logger、第三方库对象等),调用 ObjectOutputStream.writeObject() 就会立即抛出 NotSerializableException,错误信息中明确指出“哪个类型”不支持序列化。
给不可序列化字段加 transient 修饰符
这是最直接、最常用的处理方式。用 transient 告诉 JVM 跳过该字段的序列化流程,避免异常发生。
- 适用于运行期动态创建、无需持久化的资源,例如日志器、数据库连接、线程、输入流等
- 注意:反序列化后该字段值为
null(引用类型)或默认值(基本类型),不会自动恢复 - 不能对
final字段使用transient后还指望它有值——反序列化不走构造器,final字段无法被赋值
确保所有嵌套对象都可序列化
如果成员变量是自定义类对象,必须确认它自身也实现了 Serializable 接口,并且它的所有非 transient 字段也都可序列化。
- 常见陷阱:内部类默认持有外部类引用,若外部类未实现
Serializable,即使内部类自己实现了也没用 - 建议优先使用静态内部类(
static class),它不隐式引用外部实例 - 集合中的泛型元素也要可序列化,例如
List<mydata></mydata>中的MyData必须可序列化
用自定义 readObject/writeObject 恢复 transient 字段
仅加 transient 不够?需要在反序列化后重建字段值,就重写 readObject 方法。
- 先调用
in.defaultReadObject()完成默认反序列化 - 再手动初始化
transient字段,例如重新获取 Logger、打开新连接、重建缓存等 - 示例:
this.logger = LoggerFactory.getLogger(getClass());
避免把异常本身跨进程传递
在分布式或 RPC 场景中,不要让异常对象参与序列化传输——尤其当它持有了不可序列化字段(如堆栈外的上下文对象)。
- 推荐用结构化错误码 + JSON 消息替代原生异常抛出
- 若必须透传,检查异常类所有字段是否都可序列化,禁用
ThreadLocal、InputStream等敏感成员 - 生产环境更推荐使用 Jackson/Gson/Protobuf 等替代 JDK 原生序列化
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











