Java反序列化不调用构造函数,字段恢复取决于是否Serializable、非static非transient且类型可序列化;transient字段需在readObject中重建;须显式声明serialVersionUID并避免破坏性变更。

Java 对象反序列化时不会调用任何构造函数(包括无参构造),而是由 JVM 直接分配内存并按字节流填充字段。因此,**内部状态能否正确恢复,不取决于构造逻辑,而取决于字段是否可序列化、是否被 transient 修饰、是否有自定义反序列化钩子,以及类结构是否兼容**。
哪些字段会被自动恢复
默认情况下,只有满足以下条件的实例字段才会在反序列化中被还原:
- 属于实现了 Serializable 接口的类
- 不是 static(静态变量不属于对象状态)
- 不是 transient(被显式标记为不参与序列化的字段会被跳过)
- 其类型本身也支持序列化(如 String、List、自定义 Serializable 类等)
transient 字段怎么重置或重建
transient 字段不会从字节流中读取,反序列化后值为默认值(null、0、false 等)。若需在反序列化后赋予合理初始值或重建状态,必须使用 readObject 回调方法:
- 在类中声明私有方法:private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
- 第一行必须调用 in.defaultReadObject(),确保其他非 transient 字段完成还原
- 之后可安全初始化 transient 字段,例如新建 HashMap、重设时间戳、清空缓存标记等
示例:
立即学习“Java免费学习笔记(深入)”;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();
this.cache = new ConcurrentHashMap();
this.lastUpdated = System.nanoTime();
this.isValid = true;
}
保证类版本兼容性(避免 InvalidClassException)
反序列化失败常见原因是类结构变更导致 serialVersionUID 不匹配。解决方式是:
- 显式声明 private static final long serialVersionUID = 1L;(推荐用 IDE 自动生成哈希值)
- 避免删除或修改已序列化字段的类型和访问修饰符
- 新增字段可加 transient 或保持默认值语义(反序列化旧数据时该字段为 null/0)
- 慎用字段重命名——JVM 按字段名匹配,改名即视为新字段,旧数据中对应值丢失
不可序列化资源与对象行为一致性
像数据库连接、线程、文件句柄等无法序列化的资源,应标记为 transient,并在 readObject 中重建或置为安全默认态。同时注意:
- 反序列化得到的对象与原对象不是同一个实例,但逻辑状态应等价
- 若类依赖构造器中的初始化逻辑(如注册监听、启动定时任务),这些不会自动执行,需在 readObject 或单独的 init 方法中补全
- 不要在 readObject 中抛出运行时异常,否则反序列化中断且无回滚机制


















