Appearance
Java 类加载的触发时机:什么时候会初始化一个类
“类什么时候加载”这个问题,很多时候其实更准确地说,应该是:
- 类什么时候会被加载
- 类什么时候会被链接
- 类什么时候会被初始化
在日常开发里,大家最关心的通常是“什么时候会触发类初始化”。
先说最常见的触发场景
一个类在下面这些场景里,通常会触发初始化:
1. 创建类的实例
java
new UserService();这是最常见的触发方式。
2. 调用类的静态方法
java
UserService.doSomething();3. 访问类的静态变量
java
System.out.println(UserService.name);但这里要注意一个边界:
- 如果访问的是
final编译期常量,不一定会触发初始化
4. 通过反射主动使用类
java
Class.forName("com.example.UserService");5. 初始化子类时,父类通常会先初始化
如果你创建子类对象,或者主动使用子类,那么父类会先初始化。
一个更容易记的原则
你可以简单记成:
只要你对类进行了“主动使用”,就很可能触发类初始化。
常见主动使用包括:
new- 访问静态成员
- 调用静态方法
- 反射
- 初始化子类
父子类初始化顺序
日常开发里还很容易混淆“静态代码块、实例代码块、构造方法”的执行顺序。
如果涉及父类和子类,通常可以这样记:
- 父类静态变量 / 静态代码块
- 子类静态变量 / 静态代码块
- 父类实例变量 / 实例代码块
- 父类构造方法
- 子类实例变量 / 实例代码块
- 子类构造方法
你原来笔记里的核心顺序是对的,只是可以再说得更完整一点。
为什么实例代码块会在构造方法前执行
因为编译之后,实例代码块的内容会被编译器合并进构造方法里,并且通常出现在 super() 调用之后、构造方法主体逻辑之前。
所以从运行效果上看,就是:
- 先执行实例代码块
- 再执行构造方法主体剩余逻辑
一个容易误解的点
很多人会把“类加载”和“类初始化”混为一谈。
其实它们不是完全同一个阶段。
更准确地说:
- 加载:把
.class字节码读进来 - 链接:校验、准备、解析
- 初始化:真正执行类变量赋值和静态代码块逻辑
开发里我们真正关心的“静态代码块什么时候跑”,本质上说的是“类初始化什么时候发生”。
一句话总结
如果你只是想先记住最核心的判断标准,可以记这一句:
当一个类被主动使用时,通常会触发初始化;如果涉及继承,父类总是先于子类初始化。
这句话已经能覆盖绝大多数日常开发判断场景。