Java反序列化不调用构造方法,而是直接分配内存并填充字段值,以精确还原对象状态;所有构造函数体、非静态初始化块及final字段构造器赋值均被跳过,仅父类未实现Serializable时会调用其无参构造器。

Java原生序列化机制在反序列化时确实不调用任何构造方法(包括无参构造),而是直接在内存中分配对象空间并填充字段值。这是JVM底层通过特殊机制实现的,目的是绕过常规对象创建流程,避免构造逻辑干扰状态恢复。
为什么反序列化不走构造方法
构造方法可能包含初始化逻辑、校验、资源申请等副作用,而反序列化的目标是**精确还原对象当时被序列化时的状态**,不是重新“构建”一个新对象。JVM使用内部API(如Unsafe.allocateInstance)跳过构造器,直接生成对象实例。
哪些构造逻辑会被跳过
- 所有构造函数体内的代码(包括super()调用、字段赋值、日志打印、校验抛异常等)
- 非静态初始化块({ ... })
- final字段的构造器内赋值(但注意:final字段仍会按序列化时的值恢复,前提是它被正常序列化)
什么情况下构造方法仍可能被间接触发
虽然反序列化本身不调用构造器,但以下情况可能导致构造逻辑实际执行:
- 类中定义了readObject方法,且该方法里显式调用了new或this(...) —— 这属于自定义反序列化行为,已脱离标准流程
- 父类未实现Serializable,而子类实现了:此时JVM会调用父类的无参构造器来初始化父类部分(这是规范要求)
- 使用Externalizable接口:必须手动实现readExternal,其中可自由调用构造器
验证方式:写个简单测试类
定义一个带打印语句的构造器和readObject:
立即学习“Java免费学习笔记(深入)”;
public class BypassTest implements Serializable {
private static final long serialVersionUID = 1L;
public BypassTest() {
System.out.println("构造器被执行了");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("readObject被调用");
}
}
运行反序列化后,只会输出"readObject被调用",不会出现"构造器被执行了"。


















