Java类的加载过程是JVM将类的.class
文件中的二进制数据读入内存,并进行校验、转换、初始化等一系列复杂操作,最终形成可以被JVM直接使用的Java类型的过程。为了帮助你快速建立整体认知,下面这张图清晰地展示了其核心阶段和关键任务:

下面我们来详细解读每个阶段。
🔎 详解加载过程
1. 装载(Loading)
装载是类加载的第一个阶段,主要完成三件事:
- 获取二进制字节流 :通过类的全限定名(如
java.lang.String
)来获取定义此类的二进制字节流。JVM规范并未限制字节流的来源,它可以从ZIP/JAR/WAR包、网络、运行时计算生成(动态代理)或其它任何地方获取 。 - 转换静态结构 :将这个字节流所代表的静态存储结构 (Class文件格式)转化为方法区(Metaspace)的运行时数据结构 。
- 创建Class对象 :在内存中(Java堆)生成一个代表这个类的
java.lang.Class
对象,作为程序访问方法区中这些数据结构的入口 。
2. 链接(Linking)
链接阶段负责将加载到内存的类数据合并到JVM运行时环境中,可分为三个子阶段:
-
验证(Verification):确保Class文件的字节流包含的信息符合当前虚拟机的要求,不会危害虚拟机自身安全。主要包括 :
- 文件格式验证 :验证魔数(是否以
0xCAFEBABE
开头)、主次版本号等 。 - 元数据验证:对字节码描述的信息进行语义分析,如是否有父类、是否继承了不允许继承的类(final类)等 。
- 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的 。
- 符号引用验证:发生在解析阶段,确保解析动作能正确执行 。
- 文件格式验证 :验证魔数(是否以
-
准备(Preparation) :为类变量(static变量) 分配内存,并将其初始化为默认零值 (如int为0,boolean为false,引用类型为null)。注意,这里是数据类型的零值,而非代码中显式赋予的值(
public static int value = 123;
的变量value
在准备阶段后初始值为0,赋值为123的动作在初始化阶段执行)。 -
解析(Resolution) :虚拟机将常量池内的符号引用 替换为直接引用的过程 。符号引用用一组符号来描述所引用的目标,与虚拟机内存布局无关;直接引用可以是直接指向目标的指针、相对偏移量或能间接定位到目标的句柄,与虚拟机内存布局相关 。
3. 初始化(Initialization)
这是类加载过程的最后一步,真正开始执行类中定义的Java程序代码(字节码)。在此阶段,JVM会执行类构造器 <clinit>()
方法 ,该方法由编译器自动收集类中的所有类变量的赋值动作 和静态语句块(static{}块) 中的语句合并生成 。虚拟机会保证在子类的 <clinit>()
方法执行前,父类的 <clinit>()
方法已经执行完毕 。
⏰ 类初始化时机
JVM规范严格规定了有且只有以下6种情况必须立即对类进行"初始化"(而加载、验证、准备自然需要在此之前开始):
- 创建类的实例 :如
new MyClass()
。 - 访问或赋值静态变量/字段:访问某个类或接口的静态变量,或者对该静态变量赋值(被final修饰、已在编译期把结果放入常量池的静态字段除外)。
- 调用类的静态方法。
- 使用反射 :如
Class.forName("com.example.MyClass")
。 - 初始化子类:当初始化一个类时,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
- 虚拟机启动时指定的主类:当虚拟机启动时,用户需要指定一个包含main方法的主类,虚拟机会先初始化这个主类。
🧠 掌握类加载器
类加载器是实现"通过一个类的全限定名来获取描述该类的二进制字节流"这个动作的代码模块 。JVM提供了三层类加载器,遵循双亲委派模型 :
加载器类型 | 职责说明 | 父加载器 | 备注 |
---|---|---|---|
启动类加载器 (Bootstrap ClassLoader) | 加载 JAVA_HOME/lib 下的核心库(如rt.jar) |
无(由C++实现,在Java中表现为null ) | 最顶层,不继承java.lang.ClassLoader |
扩展类加载器 (Extension ClassLoader) | 加载 JAVA_HOME/lib/ext 目录下的扩展库 |
Bootstrap ClassLoader | 由 sun.misc.Launcher$ExtClassLoader 实现 |
应用程序类加载器 (Application ClassLoader) | 加载用户类路径(CLASSPATH)上的类库 | Extension ClassLoader | 也称系统类加载器,是程序的默认类加载器 |
双亲委派模型的工作过程 是:当一个类加载器收到类加载请求时,它首先不会自己去尝试加载,而是将这个请求委派给父类加载器去完成。每一层加载器都是如此,只有当所有父加载器都无法完成加载请求(在自己的搜索范围内找不到所需的类)时,子加载器才会尝试自己去加载 。这种模型的好处是:
- 避免类的重复加载,确保一个类在JVM中具有唯一性 。
- 保证Java核心API的安全 ,防止核心库被随意篡改(例如,用户自定义的
java.lang.Object
类不会被加载,因为会由顶层的Bootstrap ClassLoader加载核心的Object类)。
💎 总结
理解Java类的加载过程,对于深入理解JVM工作原理、诊断类加载相关问题(如ClassNotFoundException
, NoClassDefFoundError
)、实现热部署或进行高级框架设计都至关重要。其核心在于装载、链接、初始化 三个阶段,以及由双亲委派模型组织的类加载器体系。