Java类初始化时,静态变量赋值与静态代码块按源码顺序交替执行,共同构成<clinit>方法;父类静态部分优先于子类执行;final static编译期常量不触发初始化。

Java类初始化顺序中,代码块对静态变量的影响关键在于:只有静态代码块能参与静态变量的显式初始化,且它和静态变量赋值语句按源码顺序交替执行,共同构成类初始化阶段的核心逻辑。
静态代码块是静态变量初始化的实际执行者
静态变量在类加载“准备阶段”已被赋予默认值(如 int=0、Object=null),但真正赋予程序员指定值的操作,发生在“初始化阶段”——此时静态变量赋值语句和静态代码块按源码书写顺序依次执行。它们不是先后分两批运行,而是穿插进行:
-
谁写在前面,谁先执行:比如
static int a = getValue();写在static { b = 20; }上面,那getValue()就先调用;反之则先执行代码块 - 多个静态代码块之间也严格按出现顺序执行,不会合并或重排
- 静态代码块可以读写本类或其他已初始化类的静态字段,但不能访问任何非静态成员(this、实例变量、实例方法均不可用)
静态变量赋值与静态代码块本质同属一个初始化流程
编译后,所有静态变量初始化表达式和静态代码块都会被合并进同一个 <clinit> 方法。这意味着:
- 不存在“先批量赋值、再统一执行块”的分离阶段,二者是同一执行流中的相邻指令
- 若某静态变量初始化抛出异常(如空指针或类加载失败),后续所有静态代码块及未执行的静态变量赋值都将跳过,整个类进入初始化失败状态
- 一旦失败,后续任何对该类的主动使用(new、调用静态方法等)都会直接抛
NoClassDefFoundError
继承关系下父类静态部分必须先行完成
子类初始化必然触发父类初始化,因此静态初始化顺序天然具备层级约束:
立即学习“Java免费学习笔记(深入)”;
- JVM 保证:Grandparent 类的静态变量与静态块 → Parent 类的静态变量与静态块 → Child 类的静态变量与静态块
- 即使子类静态方法中只访问一个父类静态字段,也会完整触发父类全部静态初始化(除非该字段是编译期常量)
- 父类静态初始化未完成前,子类的任何静态成员都不会开始执行
final static 编译期常量是唯一例外
声明为 public static final int PORT = 8080; 这类基本类型或字符串字面量的常量,其值在编译时就被内联到调用处,不参与运行时类初始化:
- 引用它不会触发所在类的
<clinit>执行,静态代码块也不会运行 - 但若写成
public static final int PORT = compute();(方法调用),哪怕加了 final,也会触发完整初始化 - 这种设计让常量引用极轻量,但也意味着依赖它的初始化逻辑无法通过此类常量触发


















