静态块在类加载时执行且仅一次,按“先父后子”顺序触发,只能访问静态成员,不可用非静态内容或泛型形参,赋值与块按源码顺序执行,异常会导致类初始化失败。

静态块是类加载阶段执行的初始化逻辑,不依赖对象创建,天然适合观察父子类静态资源的加载顺序和变量可见性边界。关键在于:静态块只运行一次、按继承链自上而下触发、且不能访问非静态成员。
静态块的执行时机与触发条件
静态块属于类的 clinit 方法,仅在类首次被主动使用时执行——比如调用静态方法、访问静态字段、或 new 一个实例(前提是该类尚未初始化)。一旦执行完成,后续再 new 多少对象,静态块都不会重复运行。
- 父类未初始化时,子类无法开始初始化;JVM 强制要求“先父后子”
- 若静态块中访问了尚未声明的静态变量,编译会报错;若变量已声明但初始化语句在块之后,运行时取到的是默认值(如 int 为 0)
- 静态块中调用静态方法是安全的,只要该方法不反过来引用未初始化的静态字段
父子类静态变量与静态块的加载顺序
同一类中,静态变量赋值和静态块严格按源码书写顺序执行;跨类则遵循“父类全部静态内容 → 子类全部静态内容”的两级顺序。注意:静态变量声明本身不触发初始化,赋值动作(含构造器调用)才算。
- 父类静态变量声明并赋值 → 父类静态块(按出现顺序)
- 子类静态变量声明并赋值 → 子类静态块(按出现顺序)
- 如果父类静态块里 new 了本类实例(如 static Parent p = new Parent();),会触发父类实例初始化流程,但此时父类静态部分已执行完毕,不会打乱整体顺序
静态块中的变量可见性限制
静态块只能访问 static 修饰的成员,包括静态变量、静态方法、嵌套静态类。尝试访问 this、普通字段、非静态方法,编译直接失败。
- 即使子类继承了父类的 public 静态字段,子类静态块中也能直接使用,无需加类名前缀(如直接写 COUNT)
- 若父类静态字段是 private,子类静态块无法访问,哪怕通过反射也绕不开访问控制——因为反射调用发生在运行期,而静态块在类加载期就已完成
- 静态块内不能使用泛型类型实参(如 List
是允许的,但 T 这种形参不可用),因类型擦除后无运行时信息
实战调试建议:用日志锚定执行点
在每个静态块开头加唯一标识输出(如 System.out.println("Parent.
- 避免在静态块中做耗时操作(如 IO、网络请求),否则会阻塞整个类初始化,影响其他线程使用该类
- 若静态块抛出异常,该类进入“初始化失败”状态,后续任何访问都会抛 NoClassDefFoundError,而非原异常
- 可通过 jstat -class 或 JVM TI 工具验证类是否已完成初始化,辅助排查“静态块未执行”的假象










