Java继承体系中静态块执行本质是JVM按需触发类初始化,严格遵循“先父后子、自上而下”顺序,仅在类首次主动使用(如创建实例、调用静态方法、访问非编译期常量静态字段)时进入初始化阶段执行,而非加载阶段。

Java继承体系中静态块的执行,本质是类加载器按需触发类初始化的过程,不是靠“谁先写”或“谁被调用”决定,而是由JVM对类的首次主动使用行为驱动。关键在于分清“类加载”和“类初始化”两个阶段——静态块只在初始化阶段执行,且严格遵循“先父后子、自上而下”的顺序。
静态块执行的前提:类必须完成初始化
静态代码块不会在类被加载(Loading)时立刻运行,而是在类的初始化(Initialization)阶段才执行。这个阶段只有在以下任一情况首次发生时才会触发:
- 创建该类的实例(new MyClass())
- 调用该类的静态方法(MyClass.staticMethod())
- 访问该类的静态字段(非编译期常量,如 public static final String NAME = "A" 不触发,但 public static final String NAME = compute() 会触发)
- 反射调用(Class.forName("MyClass"),默认 initialize=true)
- 子类初始化时,若父类尚未初始化,则先触发父类初始化
父子类静态块的执行顺序:先父后子,自上而下
当某个子类首次被初始化(比如调用其静态方法),JVM会确保其直接父类已初始化。整个过程不跳过、不并行、不重排:
- 父类所有静态变量赋值语句(按源码顺序)
- 父类所有静态代码块(按出现顺序)
- 子类所有静态变量赋值语句(按源码顺序)
- 子类所有静态代码块(按出现顺序)
注意:静态变量声明与赋值是分开的。例如 static int x = getValue(); 中的 getValue() 调用发生在初始化阶段,此时它能看到前面已执行完的静态块和变量。
立即学习“Java免费学习笔记(深入)”;
类加载器层次结构本身不决定执行顺序
很多人误以为“启动类加载器→扩展类加载器→应用类加载器”的委托链会影响静态块执行顺序。其实不然:
- 同一个类只会由一个类加载器加载,且加载后由该加载器负责其初始化
- 父子类通常由同一个类加载器(如AppClassLoader)加载,执行顺序取决于继承关系和初始化时机,而非加载器层级
- 只有在涉及不同类加载器(如OSGi、热部署场景)时,类加载器隔离才可能导致同一类名被多次加载、多次初始化——但这属于高级场景,不在标准继承模型内
实战判断技巧:看“谁真正触发了初始化”
写出代码前,先问自己三个问题:
- 哪一行代码是该类第一次被主动使用?(比如 Child.say() 触发 Child 初始化)
- 它的父类是否已初始化?没初始化就先走父类流程
- 该类内部静态成员的定义顺序是否会导致依赖错乱?(如静态块里引用了尚未赋值的静态变量,会得到默认值)
只要抓住“首次主动使用 → 父类初始化 → 子类初始化”这条主线,静态块执行逻辑就清晰可推。不需要记忆口诀,只需还原JVM的初始化决策路径。


















