一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Java类加载和静态成员:代码块执行顺序的底层机理

时间:2026-06-20 09:58:52 编辑:袖梨 来源:一聚教程网

Java类初始化时静态成员按源码顺序交替执行,父类优先于子类;静态代码块在类首次主动使用时执行,编译期常量不触发初始化;new对象时先完成父子类静态初始化,再执行实例化流程。

Java 类加载过程中,静态成员的执行顺序不是随意安排的,而是由 JVM 类加载机制严格规定的初始化阶段决定的。核心在于:类初始化只发生一次,且静态代码块和静态变量赋值按源码顺序交替执行,父类优先于子类。

静态代码块何时真正执行

静态代码块在类的「初始化阶段」执行,前提是该类尚未初始化,且被首次主动使用。所谓“主动使用”包括:

  • 访问某个静态字段(非编译期常量)
  • 调用某个静态方法
  • 对类进行 new 实例操作
  • 反射调用 Class.forName("X")(默认 initialize=true)

注意:ClassLoader.loadClass("X") 不会触发初始化;而 static final 基本类型常量(如 public static final int PORT = 8080)属于编译期常量,直接内联,不触发类初始化,也就跳过静态代码块。

静态成员执行的真实顺序

同一类中,静态变量显式赋值(static int a = getValue();)和静态代码块(static { ... })按源码书写顺序从上到下交替执行,不是“先全赋值、再全执行块”。例如:

立即学习“Java免费学习笔记(深入)”;

  • 若先写 static int x = f1();,后写 static { y = f2(); },则 f1() 先调用
  • f1() 中访问了后面才声明的 static String z,此时 z 还未初始化,值为 null 或默认值(如 0),不会报编译错误,但可能引发逻辑异常
  • 多个静态块之间也严格按定义顺序执行,无法靠位置覆盖前序逻辑

父子类之间的加载依赖关系

子类初始化必然触发父类初始化,但反过来不成立。具体表现为:

  • 执行 Child.staticMethod() → 先加载并初始化 Parent(执行其全部静态成员),再初始化 Child
  • 仅访问 Parent.STATIC_FIELD → 只初始化 ParentChild 完全不参与
  • 父类静态初始化失败(如抛出 ExceptionInInitializerError)→ 整个类进入“初始化失败”状态,后续任何主动使用都会直接抛出同一异常

实例创建时的完整执行链条

当执行 new Child(),整个流程分两层展开:

  • 类初始化层(仅一次):Parent 静态变量赋值 → Parent 静态块 → Child 静态变量赋值 → Child 静态块
  • 对象实例化层(每次 new):Parent 实例变量赋值 & 实例块 → Parent 构造器 → Child 实例变量赋值 & 实例块 → Child 构造器

其中,实例块(即构造块 { ... })每次都在对应构造器体之前执行,属于对象级初始化,与静态内容完全隔离。

热门栏目