JVM类加载机制可以分为五个部分:加载、验证、准备、解析、初始化。
1.1加载
加载是加载过程中的一个阶段,这个阶段会在内存中产生一个代表这个类的java.lang.Class对象,作为方法区这个类各种数据的入口。(注意:这里不一定非要从一个Class文件中获取,也可以是ZIP文件如jar包、war包;也可以是动态加载如动态代理;也可以由其他文件生成如jsp生成对应的Class文件)
1.2验证
这一阶段主要是验证class文件字节流中包含的信息是否符号虚拟机的要求,并且不会危害虚拟机的安全。
1.3准备
准备阶段是正式为类变量分配内存并设置类的初始值阶段,即在方法区中分配这些变量所使用的内存空间。注意这里说的初始值概念,比如一个类变量定义为:
public static int v = 8080;
实际上变量v在准备阶段过后的初始值为0而不是8080,将v赋值的put static指令是在编译后,存放于类构造器方法中。
但是如果声明为:
public static final int v = 8080;
在编译阶段会为v生成ConstantValue属性,在准备阶段会根据ConstantValue属性将v赋值为8080。
1.4解析
解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程,符号引用就是class文件中的:
- CONSTANT_Class_info
- CONSTANT_Field_info
- CONSTANT_Method_info
等类型的常量。
1.4.1符号引用
符号引用与虚拟机实现的布局无关,引用的目标不一定已经加载到内存中。各种虚拟机的布局不一定相同,但是他们能接受的符号必须是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的class文件格式中。
1.4.2直接引用
直接引用可以是指向目标的指针,一个偏移量或者能间接定位目标的句柄。如果已经有了直接引用,那么引用的目标必定已经在内存中存在。
1.5初始化
初始化阶段是类加载的最后一个阶段,前面的类加载阶段中,除了类加载可以自定义加载器,其他均由JVM主导。到了初始化阶段,才开始真正意义上执行类中的Java代码。