java静态代码块仅在类首次被jvm主动使用进入初始化阶段时执行一次,触发条件包括new实例、调用静态方法、访问非final静态字段、class.forname反射加载或jvm启动运行main类,具备天然线程安全性和严格执行顺序。

Java 中静态代码块通过 JVM 类初始化机制,天然确保静态业务逻辑只执行一次、且线程安全地执行。
触发时机精准可控
静态代码块不是类一加载就运行,而是在类首次被 JVM “主动使用”进入初始化阶段时才执行。真正触发它的操作只有五种:
- 用 new 创建该类第一个实例
- 调用该类任意 static 方法
- 访问该类 非 final 静态字段(如
public static String URL = "http://api";) - 用 Class.forName("X") 反射加载(注意:
ClassLoader.loadClass()不触发) - JVM 启动时直接运行含 main() 的主类
像仅声明变量、导入包、或读取 public static final int PORT = 8080; 这类编译期常量,都不会触发初始化——业务逻辑不会被意外提前执行。
执行过程强制单次且有序
JVM 为每个类维护一个初始化标记(initialization flag),一旦完成初始化,后续所有触发行为都跳过静态代码块。这意味着:
- 反复 new 对象、多次调用 static 方法,静态块仍只执行 1 次
- 多个线程同时首次触发(如并发调用 getInstance()),JVM 自动加锁,仅一个线程执行,其余等待——无需 synchronized 或 volatile
- 同一类中多个 static 块,严格按源码从上到下顺序执行;静态变量的显式初始化(
static Map conf = loadConf();)也参与该顺序,与 static 块交替执行
父子类初始化顺序明确可靠
子类初始化时,若父类尚未初始化,JVM 强制先完成父类的全部静态初始化(包括静态变量赋值和所有 static 块),再执行子类的。这保证了继承链上的静态依赖能正确建立,比如父类定义了基础配置,子类可安全复用。
适合放什么、不能放什么
静态代码块是启动期轻量级初始化的理想位置:
-
适合:加载本地资源(
Class.getResourceAsStream())、构建不可变集合(Map.of())、校验系统属性、实现线程安全单例 - 避免:远程调用、数据库连接、启动新线程、访问其他尚未初始化类的静态成员(易引发死锁或循环依赖)
若其中抛出未捕获异常(包括 ExceptionInInitializerError),该类将永久处于“初始化失败”状态,后续任何访问都会报 NoClassDefFoundError——所以关键逻辑需做好防御性处理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











