java类初始化仅在五种主动使用情形下触发:new实例、访问非final静态字段、调用静态方法、class.forname反射、启动main类或子类初始化时父类未初始化;按父类优先、源码顺序交织执行静态赋值与static{}块,且仅执行一次。

Java 类被主动加载并初始化,发生在 JVM 判定该类“首次被主动使用”时。注意:加载(Loading)和初始化(Initialization)是两个不同阶段,但只有满足特定条件,才会触发完整的初始化流程——也就是执行静态变量赋值和 static{} 块。
必须触发初始化的五种情况
虚拟机规范明确规定,有且仅有以下五种场景会强制类进入初始化阶段:
- 执行 new 指令创建该类或其子类的实例(如
new MyClass()) - 读取或修改该类的非 final 静态字段(如
MyClass.count++;但MyClass.CONSTANT不会,因为编译期已内联) - 调用该类的静态方法(如
MyClass.doWork()) - 通过 Class.forName("MyClass") 反射加载(
ClassLoader.loadClass()仅加载不初始化) - JVM 启动时直接运行含 main() 方法的主类;或初始化某个子类时,其父类尚未初始化,则先初始化父类
常见误区:哪些操作不会触发初始化
这些属于“被动引用”,只可能触发类加载(到准备阶段),但跳过初始化:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 仅声明引用类型变量(如
MyClass obj;) - 创建该类的数组(如
MyClass[] arr = new MyClass[10];) - 访问 public static final 编译期常量(如
int PORT = 8080;),其值已被复制到调用方常量池 - 通过子类名引用父类定义的静态字段(如
Son.NUM,而NUM在Father中定义且非 final)——只会初始化Father,Son不触发
初始化过程的关键顺序规则
一旦触发初始化,JVM 严格按以下逻辑执行:
-
父类优先:先完成父类全部静态变量赋值和
static{}块(按源码文本顺序),再执行子类对应部分 -
文本顺序交织:同一类中,静态变量显式赋值与
static{}块按代码出现顺序交替执行,不是“先赋值后跑块” - 仅一次:整个生命周期中,每个类的初始化阶段最多执行一次;后续 new 实例、调用静态方法均不再重复执行静态块
初始化阶段实际做了什么
它执行的是类构造器
- 所有静态变量的显式赋值语句(如
static int x = 5;) - 所有
static{}代码块中的语句 - 若存在静态字段依赖其他静态方法或字段,需注意初始化顺序——后声明的静态成员在前序块中访问时仍为默认值(
null、0、false)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










