java反序列化不执行任何构造方法,包括无参构造,因jvm直接调用unsafe.allocateinstance分配内存并填充字段值,跳过类初始化和构造逻辑;仅当父类未实现serializable时,才被迫调用其可访问的无参构造器初始化父类字段。

Java 反序列化不执行任何构造方法,包括无参构造,是因为它根本就不是通过 new 指令创建对象的。JVM 用的是底层绕过类初始化流程的机制,直接分配内存并填充字段值。
反序列化跳过构造器的底层依据
JVM 在反序列化时调用的是类似 Unsafe.allocateInstance(Class) 的内部原语。这个方法:
- 只负责在堆上开辟一块内存空间,大小按类的字段布局计算
- 不触发类的初始化(
<clinit></clinit>),也不执行任何构造逻辑(<init></init>) - 后续由
ObjectInputStream按字段声明顺序,把字节流里的值逐个写入对应内存偏移位置
为什么不能走常规 new 流程
如果强制调用构造器,会破坏反序列化的核心目标——精确还原状态。比如:
- 构造器里
this.id = UUID.randomUUID()会导致反序列化后 ID 变更 - 非静态初始化块中
list = new ArrayList()会覆盖流中已存的 list 元素 - 校验逻辑如
if (name == null) throw new IllegalArgumentException()会让合法的序列化数据加载失败
父类无参构造被调用的唯一例外
这个“例外”其实不是反序列化主动调用,而是 JVM 被迫补全不可序列化父类的状态:
- 当父类未实现
Serializable,它的字段不会出现在字节流中 - JVM 必须让父类部分处于可使用状态,于是调用其**可访问的无参构造器**来初始化父类字段(如 int → 0,Object → null)
- 此时子类自己的构造器依然不执行;执行的只是父类的无参构造,且仅限于该父类本身
如何验证构造器真没运行
在类中同时放构造日志和 readObject:
public MyClass() { System.out.println("constructor"); }private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println("readObject"); }
反序列化后只会输出 readObject,constructor 完全静默——这说明控制权从未交到构造器手上。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











