静态代码块在类初始化阶段执行且仅一次,由首次主动使用触发,按源码顺序执行,父类先于子类;访问编译期常量或仅声明引用不会触发,异常会导致类永久初始化失败。

静态代码块在类加载时并不立即执行,而是在 JVM 进入「类初始化阶段」时才运行,且仅一次。它不是“一加载就触发”,而是等类被首次主动使用时才真正初始化数据。
什么时候真正触发静态代码块
只有以下操作会触发类初始化,从而执行静态代码块:
- 用 new 创建该类或其子类的实例
- 调用该类的 public static 方法
- 访问该类的 非编译期常量静态字段(如 public static int PORT = 8080;)
- 通过 Class.forName("X") 反射加载(注意:ClassLoader.loadClass() 不会触发)
- 子类初始化时,父类若未初始化,会先触发父类初始化
特别注意:public static final String MSG = "hello"; 这类编译期常量,引用它不会触发初始化,静态代码块也不会运行。
静态代码块怎么写、怎么安排顺序
语法很简单:用 static {} 包裹初始化逻辑,不能加访问修饰符,也不能带参数或返回值。
同一类中多个静态代码块,以及静态变量赋值语句,全部按源码从上到下严格交替执行:
- static int a = getValue(); → 立即执行 getValue()
- static { b = compute(); } → 紧接在前一句之后运行
- 后续的 static {} 块继续按书写顺序执行
如果 getValue() 中访问了后面才声明的 static 字段,读到的是默认值(0、null、false),不是编译错误,但可能引发逻辑问题。
继承关系下的执行顺序
当 new 子类对象时,静态部分执行顺序固定为:
- 父类所有静态变量赋值 → 父类所有静态代码块(按源码顺序)
- 子类所有静态变量赋值 → 子类所有静态代码块(按源码顺序)
这个顺序不可跳过或颠倒,哪怕子类没用到父类任何静态成员,只要子类初始化,父类就必须先完成初始化。
初始化数据时要注意什么
静态代码块适合做一次性全局准备,比如加载配置、预热缓存、注册驱动,但必须避开几类风险:
- 抛出未捕获异常(如 IOException、NullPointerException)会导致 ExceptionInInitializerError,类永久不可用
- 避免耗时操作(网络请求、大文件读取),否则会卡住整个类加载过程
- 不能访问 this 或调用非 static 成员(编译直接报错)
- 跨类依赖要小心加载顺序——若 A 的静态块依赖 B 的静态字段,而 B 尚未初始化,可能拿到 null 或默认值
推荐把复杂逻辑封装成 private static 方法,在静态块中调用,便于测试和维护。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











