类加载的过程
- 加载
- 验证
- 准备
- 解析
- 初始化
- 使用
- 卸载
其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的。而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也称为动态绑定)。 另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。
加载
1、通过一个类的全限定名来获取其定义的二进制字节流。
2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。3、在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
相对于加载的其他阶段而言,加载阶段(准确地说,是加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,因为开发人员既可以使用系统提供的类加载器来完成加载,也可以自定义自己的类加载器来完成加载。
验证
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致会完成4个阶段的检验动作:
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
准备
为类的静态变量分配内存,并将其初始化为默认值。
这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。
解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
符号引用就是用一组符号来描述目标,其被引用的类、方法或者变量还没有被加载到内存中。而直接引用就是直接指向目标的指针,被引用的类、方法或者变量已经被加载到内存中。以变量举个例子:
/**
* 符号引用
*/
String str = "aaa";
System.out.println("str="+str);
/**
* 直接引用
*/
System.out.println("str="+"abc");
当解析步骤的完成,意味着整个连接部分的完成。这也就是说外部加载的Java类已经成功地引入到了你的程序中。
初始化
JVM执行代码中的资源初始化操作:
成员变量的赋值动作、静态变量的赋值动作、以及静态代码块的逻辑等。
使用
类访问方法区内的数据结构的接口, 对象是Heap区的数据。
卸载
Java虚拟机将结束生命周期的几种情况
- 执行了System.exit()方法
- 程序正常执行结束
- 程序在执行过程中遇到了异常或错误而异常终止
- 由于操作系统出现错误而导致Java虚拟机进程终止