静态代码块和静态成员变量按源码顺序交替执行;父类静态部分先于子类执行;编译期常量不触发初始化;静态初始化失败导致后续访问抛noclassdeffounderror。

静态代码块和静态成员变量没有绝对的“谁优先”,它们按源码中出现的顺序交替执行。
同一类中:谁在前面就先执行谁
静态变量赋值语句(如 static int x = getValue();)和静态代码块(static { ... })在字节码中被合并进同一个
- 如果先写 static int a = f1();,后写 static { b = f2(); },那么 f1() 先调用
- 若 f1() 中访问了后面才声明的 static String c,此时 c 还未执行初始化,值为 null 或默认值(如 0),不会编译报错,但可能引发运行时逻辑问题
- 多个静态块之间也完全按定义位置从前到后执行,无法靠后置代码覆盖前置逻辑
父子类之间:父类静态部分一定先于子类
子类初始化必然触发父类初始化,但父类初始化不会导致子类初始化。JVM 保证执行链条是单向的:
- 调用 Child.staticMethod() → 先完整执行 Parent 的所有静态成员(变量赋值 + 静态块,按序),再执行 Child 的静态成员
- 仅访问 Parent.STATIC_FIELD(非编译期常量)→ 只初始化 Parent,Child 不参与
- 若父类静态初始化失败(如抛出 ExceptionInInitializerError),整个类进入“初始化失败”状态,后续任何访问都会直接抛 NoClassDefFoundError
注意编译期常量不触发初始化
像 public static final int VERSION = 1; 这类基本类型、字符串的 final static 常量,在编译阶段就被内联到调用处,不会引起类加载,也就跳过静态代码块和变量初始化。
- 访问它等价于直接写数字 1,JVM 完全不加载该类
- 但换成 public static final Integer PORT = 8080;(包装类型)或 public static final String MSG = new String("hello");,就不再属于编译期常量,会正常触发初始化
静态初始化失败会导致类不可用
只要静态变量赋值或静态代码块中抛出未捕获异常(如 NullPointerException),整个类初始化即告失败:
- 后续对该类的任何主动使用(new、调用静态方法、访问非final静态字段等)都会立即抛出 NoClassDefFoundError
- 这个错误不是 ClassNotFoundException,说明类已加载成功,只是初始化失败了
- 无法通过重试或重新加载修复,必须修正静态初始化逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











