1、概述
虚拟机把描述类的数据从Class文件加载到内存,并对数据校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
与那些在编译时需要进行连接工作的语言不通,在Java语言里,类型的加载、连接和初始化过程都是在程序运行期间完成的,这位Java应用程序提供了高度的灵活性,Java里面天生可以动态扩展的语言特性就是就是依赖运行期间动态加载和动态连接这个特点实现的。
2、类加载时机
类从被加载到虚拟机内存开始到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中验证、准备、解析这3个阶段统称为连接(Linking)。
图中,连接即是验证、准备、解析的阶段。
加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化话阶段之后再开始,这就是为了支持Java语言的运行时绑定(也称为动态绑定)。注意,它们是按部就班地“开始”,但不是按部就班地“进行”,因为这些阶段通常都是互相交叉地进行的,通常会在一个阶段执行的过程中调用、激活另一个阶段。在某些特殊的情况下,初始化在解析之前开始。
3、类加载过程
(1)加载:在加载阶段,虚拟机需要完成以下3件事
a、通过一个类的全限定名来获取定义此类的二进制字节流。
b、将这个字节流所代表的静态存储结构转化成为方法区的运行时数据结构。
c、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区的各种数据的访问入口。
(2)验证:验证是连接的第一步,其目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证大致会完成文件格式验证(保证输入的字节流能正确地解析并存储于方法区内,格式上符合描述一个Java类型信息的要求)、元数据验证(对类的元数据信息进行语义校验)、字节码验证、符号引用验证(确保解析 动作正常执行)4个阶段。
(3)准备:准备阶段正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,适量变量将会在对象实例化时随着对象一起分配在Java堆中。这里所说的初始值一般为数据类型的零值。
(4)解析:解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程
(5)初始化:根据程序员通过程序制定的主观计划区初始化类变量和其他资源,或者可以理解为初始化阶段是执行类构造器<clinit>()方法的过程。
参考文献
《深入理解Java虚拟机》 机械工业出版社 周志明著