java类加载和对象初始化顺序由jvm严格保证:类加载阶段先父类静态代码块再子类静态代码块;对象实例化阶段依次执行父类构造代码块、父类构造方法、子类构造代码块、子类构造方法。

Java 类加载和对象初始化的执行顺序,本质是由 JVM 的类加载机制与对象实例化流程共同决定的,并非人为约定,而是有明确的底层逻辑支撑。
类加载阶段:父类静态代码块先于子类执行
当首次主动使用子类(如 new Son())时,JVM 触发类加载。由于子类字节码中包含对父类符号引用(比如继承关系、调用父类静态字段或方法),类加载器必须先确保父类已加载并完成初始化,否则无法安全解析子类结构——这是「双亲委派模型」在初始化阶段的延伸体现。
具体过程如下:
- JVM 检查 Parent.class 是否已加载;若未加载,则委托上级加载器尝试加载,最终由启动类加载器完成加载
- 加载完成后,执行 Parent 的静态初始化:按源码顺序依次执行静态变量赋值与静态代码块(static{}),且仅一次
- 接着加载 Son.class,再执行其静态变量赋值与静态代码块
这个阶段不涉及任何对象创建,只与类的定义结构和依赖关系有关。
对象实例化阶段:父类构造代码块与构造方法优先于子类
当执行 new Son() 时,JVM 开始分配内存、设置默认值、执行实例初始化。关键在于:每个子类构造方法第一行默认隐含 super()(除非显式调用其他父类构造器),这强制要求父类构造逻辑必须先完成。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
而父类构造方法执行前,JVM 会先处理父类的实例初始化部分:
- 为父类所有实例变量赋予默认值(如 int → 0,Object → null)
- 按源码顺序执行父类的构造代码块({})——这些代码块本质上被编译器合并进每个构造方法的开头
- 再进入父类构造方法体执行
- 父类初始化完毕后,才回到子类,重复相同流程:实例变量赋默认值 → 子类构造代码块 → 子类构造方法
这种设计保障了继承链上的对象状态是自上而下、逐层构建的,避免子类访问尚未初始化的父类字段。
字节码层面的关键证据
反编译 javap -c 可见:
- 静态代码块内容被编译进
方法(类初始化方法),该方法由 JVM 在类加载完成时自动调用 - 构造代码块内容被编译器“复制”到每一个构造方法的开头(在 super() 或 this() 调用之后、构造体之前)
-
super() 对应字节码指令 invokespecial,它必须在父类
方法执行完毕后才能返回
也就是说,执行顺序不是靠“语法糖”维持,而是由字节码结构与 JVM 规范严格保证的。
为什么不能颠倒?——内存与语义安全约束
如果允许子类静态块先执行,可能引用尚未加载的父类静态字段,导致 NoClassDefFoundError;如果允许子类构造逻辑先于父类执行,就可能出现访问未初始化的父类成员,破坏封装性与对象一致性。JVM 通过分阶段、强依赖的初始化协议,从根本上规避了这类风险。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










