Java的类加载过程是将类从其二进制表示(通常是一个 .class 文件)加载到JVM中并准备使用的过程。这个过程分为三个主要阶段:加载(Loading)、链接(Linking)和初始化(Initialization)。每个阶段都有其特定的任务和细节。以下是对这些阶段的详细解释:
1. 加载(Loading)
加载阶段 是指将类的二进制数据读取到内存中,并在内存中创建一个表示该类的Class对象。
具体步骤:
- 定位类文件:类加载器(ClassLoader)定位到类的字节码文件(.class文件)。类加载器可以从不同来源加载类文件,如本地文件系统、网络、JAR包等。
- 读取类文件:类加载器将类文件的二进制数据读取到内存中。
- 创建Class对象:根据读取到的二进制数据,Java虚拟机在方法区中创建一个Class对象来表示该类。
2. 链接(Linking)
链接阶段 将包括验证、准备和解析三个子阶段,将类的二进制数据合并到JVM的运行时环境中。
具体步骤:
-
验证(Verification):
- 确保类文件的字节码符合Java语言规范和JVM规范。主要目的是保证类文件的安全性和正确性,防止恶意字节码的执行。
- 检查类的结构、字段、方法的字节码,以及符号引用的合法性。
-
准备(Preparation):
- 为类的静态变量分配内存,并将其初始化为默认值。例如,基本类型初始化为其默认值(如0、null等),而引用类型则初始化为null。
- 在方法区中分配这些变量所需的内存空间。
-
解析(Resolution):
- 将类的常量池中的符号引用(Symbolic References)替换为直接引用(Direct References)。
- 符号引用是以字符串形式描述的引用,例如类名、字段名和方法名。解析阶段将这些字符串形式的符号引用转换为实际的内存地址或偏移量。
3. 初始化(Initialization)
初始化阶段 是执行类构造器()方法的过程,这是类加载过程的最后阶段。
具体步骤:
-
类变量初始化:
- 执行类变量的初始化语句。例如,静态变量的赋值和静态代码块(static block)会在这个阶段执行。
- 这些初始化语句按照它们在类中的出现顺序执行。
-
静态代码块执行:
- 执行静态代码块中的代码。静态代码块是在类被加载时自动执行的代码块,可以包含任意的代码逻辑。
- 这些静态代码块只执行一次,即在类初始化阶段。
类加载器(ClassLoader)
Java的类加载机制由类加载器(ClassLoader)负责。Java虚拟机中存在三种主要的类加载器:
- 启动类加载器(Bootstrap ClassLoader):
- 加载核心Java类库(如rt.jar中的类),用本地代码实现,不是Java类。
- 扩展类加载器(Extension ClassLoader):
- 加载Java扩展库(通常位于
<JAVA_HOME>/lib/ext
目录)。
- 加载Java扩展库(通常位于
- 应用程序类加载器(Application ClassLoader):
- 加载应用程序的类路径(classpath)上指定的类,是默认的类加载器。
类加载过程示例
例如,加载一个简单的类MyClass
,过程如下:
- 加载:类加载器读取
MyClass.class
文件,生成对应的Class对象。 - 链接:
- 验证:检查
MyClass
的字节码格式和结构是否合法。 - 准备:为
MyClass
的静态变量分配内存并初始化为默认值。 - 解析:将符号引用解析为直接引用。
- 验证:检查
- 初始化:执行
MyClass
的静态初始化代码,包括静态变量的赋值和静态代码块。
通过这三个阶段,Java虚拟机能够确保类在使用前已经正确加载、链接和初始化,从而保证程序的稳定性和正确性。