一个类从加载到应用,个别会经验上面的这个过程:
加载 -> 验证 -> 筹备 -> 解析 -> 初始化 -> 应用 -> 卸载
1. 加载
编译:
X.java->X.class->JVM
class 汇总的类的加载
双亲委派模型: 子类加载器会请示父类加载器查看层层上询, 下面没加载的, 再层层下派;
- 启动类加载器: Bootstrap ClassLoader
- 扩大类加载器: Extension ClassLoader
- 应用程序类加载器: Application ClassLoader
- 自定义类加载器: XXX
自定义加载器 ->Application->Extension->Bootstrap
2. 验证
校验你加载进来的.class 文件内容,是否合乎 Java 虚拟机标准
-
- 格局验证: 0xCAFEBABE 结尾 / 是否有编码以外的字符等
-
- 元数据验证: 比方是否继承了 final 类(不容许的)/ 父类为接口或抽象类的子类, 是否实现了形象办法等;
-
- 字节码验证: 办法调用时任何指令不会跳到办法体以外的的字节码指令上;
-
- 符号援用验证: 符号援用类中的类 / 字段 / 办法的可拜访性(是否能被以后类拜访)
3. 筹备
static 变量: 分配内存空间,设置默认的初始值
byte/short/int/long->0/0L
float/double=0.0f/0.0d
boolean=false
reference=null
4. 解析
符号援用替换为间接援用的过程
间接援用 : 指标的指针 / 绝对偏移量 / 间接定位到指标的句柄
符号援用: class 文件中的字面符号援用;
就是将 classs 文件中的类 / 接口 / 字段 / 办法解析为理论的指标指针 / 绝对偏移量 / 指标句柄等的过程;
起因就是: classs 文件是编译来的; 编译的时候并无奈得悉执行时类 / 接口 / 字段 / 办法的内存地位.
5. 初始化
初始化变量为理论赋值的数据;
如 static int a = getValue()
在筹备阶段只会给 a 调配空间和给初始值 0, 在初始化阶段才会调用 getValue()来赋值初始化 a;
6. 应用
略
7. 卸载
略