在 Java 中,类的加载是一个动态过程,通常发生在程序运行时,而不是编译时。类加载是由 Java 虚拟机(JVM)负责的,主要由 类加载器(ClassLoader) 完成。通常,当类第一次被使用时,类加载器会负责将类文件加载到 JVM 中,并完成必要的初始化过程。如果没有明确的使用,类可能永远不会被加载。
一般来说,类的加载大致发生在以下几种情况下:
1. 第一次使用类时
- 当类或接口首次被主动使用时,JVM 会加载该类。例如:
- 创建类的实例(使用
new
关键字)。 - 访问类的静态变量(如
ClassName.staticVar
)。 - 调用类的静态方法(如
ClassName.staticMethod()
)。 - 使用反射(如
Class.forName("ClassName")
)。
- 创建类的实例(使用
这些情况会触发 JVM 加载类文件。
2. 子类加载时
- 当子类被加载时,如果其父类尚未被加载,JVM 会先加载父类。因为子类初始化之前,必须确保其父类已经初始化过。
3. 动态加载类
- 使用反射(如
Class.forName()
)或者自定义类加载器(ClassLoader
的子类)可以手动触发类的加载过程。这种方式允许程序根据运行时的需求动态加载类。
4. 访问类的常量
- 如果类的常量是编译时常量(如
final static
变量),JVM 可能不会在访问常量时立即加载该类,因为常量的值已经在编译时确定,并可能在调用方的字节码中直接使用。
类加载的三个阶段
-
加载(Loading)
- JVM 通过类加载器将类文件加载到内存中,并创建一个
Class
对象来表示该类。
- JVM 通过类加载器将类文件加载到内存中,并创建一个
-
连接(Linking)
- 包括三个步骤:
- 验证(Verification): 确保类的字节码符合 JVM 的规范。
- 准备(Preparation): 为类的静态变量分配内存并赋初值(如
int
变量的默认值为 0)。 - 解析(Resolution): 将类的符号引用解析为直接引用(即将类、字段、方法等的符号引用替换为具体的内存地址)。
- 包括三个步骤:
-
初始化(Initialization)
- 执行类的静态初始化块(
static {}
)和静态变量的初始化语句。
- 执行类的静态初始化块(