静态代码块在jvm类初始化(initialization)阶段执行且仅一次,按源码顺序与静态变量赋值交替运行,父类优先于子类;仅在类首次主动使用时触发,编译期常量访问不触发,异常导致类永久初始化失败。

Java 类初始化阶段执行静态代码块,不是“一加载就跑”,而是等类被首次主动使用时才触发,且只执行一次。关键在于它和静态变量赋值语句混在一起,按源码从上到下交替运行,父类优先于子类。
静态代码块在哪个阶段执行
它属于 JVM 类初始化(Initialization)阶段,不是类加载(Loading)或链接(Linking)阶段。这个阶段只发生一次,前提是该类尚未完成初始化,并满足以下任一“主动使用”条件:
- 用 new 创建该类实例
- 调用该类的 public static 方法
- 访问该类的 非编译期常量的 public static 字段(如 public static int PORT = 8080;)
- 通过 Class.forName("Xxx") 反射加载(默认 initialize=true)
- 该类含有 main() 方法 并作为程序入口启动
注意:public static final String MSG = "hello"; 这类编译期常量不触发初始化,静态代码块完全跳过。
同一类中多个静态代码块怎么排顺序
它们和静态变量显式赋值语句(如 static String s = init();)共享一个执行序列,严格按源码书写顺序从上到下交替执行:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 先出现的静态变量赋值,就先执行其初始化表达式
- 紧接着遇到 static { },就立即执行其中代码
- 后续同理,顺序即声明顺序,不可覆盖、不可重排
例如:若先写 static int x = f1();,后写 static { y = f2(); },则 f1() 一定先调用;若 f1() 中访问了后面才定义的 static String z,此时 z 值为 null 或默认值(如 0),不会编译报错,但可能引发运行时逻辑异常。
继承关系下父子类静态块谁先执行
只要触发子类初始化(比如 new Child()),JVM 就强制先完成父类的整个静态初始化流程:
- 先执行 Parent 类中所有静态变量赋值 + 静态代码块(按源码顺序)
- 再执行 Child 类中所有静态变量赋值 + 静态代码块(同样按源码顺序)
这个过程全局只发生一次。后续无论 new 多少次 Child 实例,或调用多少次 Child 的静态方法,静态块都不会再次执行。
异常会带来什么后果
如果任意静态代码块或静态变量初始化过程中抛出未捕获异常(如 NullPointerException、IOException),JVM 会标记该类为“初始化失败”状态。此后任何对该类的主动使用,都会直接抛出 ExceptionInInitializerError,不再尝试重新初始化。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










