java静态代码块在类初始化阶段执行且仅一次,触发条件包括new实例、调用静态方法、访问非final静态字段、class.forname反射加载(非classloader.loadclass)、子类初始化或jvm启动main类,按源码顺序及继承链自顶向下执行。

Java中静态代码块(static块)**不能被反射直接调用**,它也不是一个可调用的方法或成员,而是类加载过程中的初始化逻辑。它的执行时机由JVM控制,与反射无关;反射操作(如Class.forName()、clazz.getDeclaredConstructor().newInstance()等)可能**间接触发**静态块执行,但本质是触发了类的初始化,而非“调用”静态块。
静态块的执行时机:取决于类初始化阶段
静态块在类的**初始化阶段**执行,且只执行一次。JVM规范规定,以下情况会触发类的初始化(从而执行静态块):
- 首次主动使用该类的静态字段(读取或赋值,不包括声明时的常量默认值)
- 首次调用该类的静态方法
- 使用
new关键字创建该类实例 - 通过反射(如
Class.forName("com.example.MyClass"))加载并初始化类(注意:Class.forName(name, false, loader)中第二个参数为false时不初始化) - 子类初始化时,若父类尚未初始化,则先初始化父类
- 使用JDK1.7+的动态语言支持(如
MethodHandle)首次解析到该类的静态方法句柄
反射如何影响静态块执行?关键看是否触发初始化
反射本身不“调用”静态块,但某些反射API会触发类初始化:
-
Class.forName("X")→ 等价于Class.forName("X", true, currentClassLoader)→ 触发初始化 → 执行静态块 -
ClassLoader.loadClass("X")→ 仅加载,不初始化 → 静态块不执行 -
Class.forName("X", false, loader)→ 显式禁用初始化 → 静态块不执行 -
MyClass.class(字面量引用)→ 类已加载,但若尚未初始化,不会自动触发初始化;只有后续真正使用(如访问静态字段)才触发
静态块执行顺序:按源码出现顺序 + 继承链自顶向下
同一类中多个static块按代码书写顺序依次执行;涉及继承时,遵循“父类静态块 → 子类静态块”的顺序(前提是父类已被初始化):
- 父类静态字段赋值、静态块按文本顺序执行
- 子类静态字段赋值、静态块按文本顺序执行
- 这个顺序在类初始化时严格保证,与反射与否无关
例如:class Parent { static { System.out.println("Parent"); } } 和 class Child extends Parent { static { System.out.println("Child"); } },首次使用Child时输出为:Parent → Child。
控制静态块执行时机的实用建议
若需延迟或避免静态块执行,核心是控制类初始化时机:
- 用
ClassLoader.loadClass()代替Class.forName(),避免意外初始化 - 将初始化逻辑从静态块移至显式静态方法中,按需调用(如
MyClass.init()) - 使用单例模式或Holder类(利用类初始化惰性)实现延迟初始化
- 避免在静态块中做耗时或依赖外部环境的操作——它不可重入、不可中断、无法重试
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











