静态代码块在类首次被主动使用时执行,而非项目一启动就运行;触发时机包括new实例、调用public static方法、访问非final静态字段、Class.forName反射加载;应避免耗时操作,适合轻量无依赖初始化。

静态代码块在项目启动时执行,但不是“一启动就跑”,而是在类首次被主动使用时才触发——这个时机点直接影响启动耗时和初始化可靠性。
哪些操作真正触发静态代码块
只有以下行为会让JVM进入类的初始化阶段,从而运行静态代码块:
- 用 new 创建该类第一个实例
- 调用该类任意 public static 方法
- 访问该类的非 static final 基本类型常量 静态字段(如 public static String API_URL 会触发,public static final int TIMEOUT = 3000 不会)
- 通过 Class.forName("X") 反射加载(注意:ClassLoader.loadClass("X") 不会触发)
- JVM 启动时直接运行含 main() 的主类
启动性能的关键陷阱
静态代码块里做耗时操作(比如读大配置文件、连远程服务、解析复杂JSON),会卡住整个类的初始化流程。一旦多个核心类都这么写,启动时间就明显拉长。
- 建议把重操作移到懒加载逻辑中,例如用 Holder 模式 或 ConcurrentHashMap.computeIfAbsent 延迟执行
- 必须在启动时完成的初始化,应加日志标记起止时间,方便定位瓶颈
- 避免在块内抛出未捕获异常——会导致类初始化失败,后续所有调用都抛 NoClassDefFoundError
适合放什么内容
静态代码块最适合做轻量、确定、无依赖的全局准备:
立即学习“Java免费学习笔记(深入)”;
- 预设不可变配置:数据库 URL、默认超时值、枚举映射表
- 注册驱动或 SPI 扩展(如 JDBC 4.0+ 前需 Class.forName)
- 初始化线程安全的静态缓存(如 static final Map + unmodifiableMap)
- 校验关键系统属性是否存在(如 System.getProperty("env"))
顺序与协作细节不能忽略
静态变量赋值和静态代码块按源码从上到下交替执行,不是“先全赋值再执行块”:
- static String A = initA(); 和 static { B = initB(); } 写在一起时,若 initA() 里用了 B,拿到的是默认值(null / 0)
- 子类初始化前,父类静态块一定已执行完毕,可放心复用父类静态资源
- 不能在块里用 this 或 new 当前类实例——此时对象尚未构造,容易引发循环初始化


















