1. JVM类装载
类装载(Class Loading)是Java虚拟机(JVM)将类的字节码文件(.class文件)加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被JVM直接使用的Java类型的过程。
这是Java程序运行的基础机制,也是实现Java"一次编写,到处运行"特性的关键环节。
类装载的核心目标是:
将类的二进制数据读入内存
将静态存储结构转换为运行时数据结构
生成对应的Class对象作为访问入口
确保加载的类安全有效
2. 类装载的生命周期
类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载这7个阶段。
其中,验证、准备和解析这三个部分统称为连接(linking)
1. 加载(Loading)
任务:查找并加载类的二进制数据
过程:
通过类的全限定名获取类的二进制字节流
将字节流代表的静态存储结构转换为方法区的运行时数据结构
在堆中生成一个代表该类的Class对象,作为方法区数据的访问入口
特点:
数组类由JVM直接创建,不通过类加载器
非数组类的加载可以通过内置或自定义的类加载器完成
2. 验证(Verification)
目的:确保Class文件的字节流符合JVM规范,不会危害虚拟机安全
验证内容:
文件格式验证(魔数、版本号等)
元数据验证(语义分析)
字节码验证(程序逻辑验证)
符号引用验证(常量池中的引用检查)
3. 准备(Preparation)
任务:为类变量分配内存并设置初始值
特点:
只分配类变量(static变量),不包括实例变量
初始值通常是数据类型的零值(如0、0L、null、false等)
对final static常量会直接赋程序指定的值
4. 解析(Resolution)
任务:将常量池中的符号引用替换为直接引用
解析类型:
类或接口的解析
字段解析
方法解析
接口方法解析
特点:
解析可能在初始化之后才进行(动态绑定)
如果解析失败会抛出NoSuchMethodError等错误
5. 初始化(Initialization)
任务:执行类构造器
<clinit>()
方法过程:
按顺序执行静态变量赋值和静态代码块
保证父类的
<clinit>()
先于子类执行接口的
<clinit>()
不需要先执行父接口的
触发条件(以下情况必须立即初始化):
使用new、getstatic、putstatic或invokestatic指令时
反射调用类时
初始化子类发现父类未初始化时
虚拟机启动时指定的主类
使用动态语言支持时相关方法句柄对应的类未初始化
<clinit>()
方法详解
<clinit>()
是Java编译器自动生成的类构造器方法(Class Constructor Method),它负责执行类的初始化工作。这个特殊的方法名称中的"clinit"是"class initialization"的缩写。
自动生成:
由编译器自动收集类中的所有静态变量赋值语句和静态代码块(static{}块)合并产生
如果没有静态变量赋值或静态代码块,编译器不会生成
<clinit>()
方法执行顺序:
父类的
<clinit>()
先于子类执行静态变量和静态代码块按源代码中的出现顺序执行
接口的
<clinit>()
不需要先执行父接口的(除非使用父接口的变量)线程安全:
JVM会保证一个类的
<clinit>()
方法在多线程环境下被正确地加锁同步如果一个线程正在执行
<clinit>()
,其他线程会阻塞等待
6. 使用(Using)
类完成初始化后进入使用阶段
可以创建实例、调用方法、访问字段等
7. 卸载(Unloading)
条件:
类的所有实例都已被回收
加载该类的ClassLoader已被回收
对应的Class对象没有被引用
特点:
由JVM的垃圾回收器完成
卸载通常发生在方法区(元空间)垃圾回收时
由启动类加载器加载的类通常不会被卸载
3. 总结
类装载的执行过程?
- 加载:查找和导入class文件
- 验证:保证加载类的准确性
- 准备:为类变量分配内存并设置类变量初始值
- 解析:把类中的符号引用转换为直接引用
- 初始化:对类的静态变量,静态代码块执行初始化操作
- 使用:JVM 开始从入口方法开始执行用户的程序代码
- 卸载:当用户程序代码执行完毕后,JM便开始销毁创建的Class对象。
上一篇 下一篇