类加载过程本质上就是类加载器根据类的全限定名称去找到对应的class字节码文件内容,然后将字节码文件的内容加载到虚拟机方法区中的过程。
所以我们大体上可以把类加载的过程分为三部分:
1、加载,就是获取到class文件的内容
2、链接,就是把相应的文件内容添加到虚拟机中,转变为虚拟机中的class对象,使虚拟机可以使用该类
3、初始化,初始化类对象的中的数据
也就是下面这个样子
而链接其实是一个较为复杂的过程,所以我们把链接再拆分成
验证、准备、解析三个更细粒度的步骤,所以总体的步骤如下图:
而每个步骤更为详细的解释:
1、加载-根据全限定名称去寻找这个class的字节码文件内容,然后根据字节码中的内容翻译成jvm所熟知的class数据结构并保存到内存中。
注意这里的寻找字节码文件并不一定局限在传统的从磁盘中查找,而是非常灵活的,可以来自于db,来自于内存,来自于网络,甚至动态生成。
这里也为class文件的安全存储提供了保证。
2、验证-为了防止字节码文件存在恶意的信息,或者有伤害虚拟机的行为,因此需要对字节码文件的内容进行一个全面的校验。包括字节码的格式。语义、操作验证等。
3、准备-为类的静态变量分配内存并赋予对应的默认值。如int 赋予0,对象赋予null,boolean赋予false等。
4、解析-将常量池中的符号引用转化为直接引用。也就是说将各种对象/方法的符号名称直接替换为方法区中的指针或者地址偏移量,以便直接调用该对象/方法。
5、初始化-会将所有的静态变量的值进行一遍初始赋值的操作。同时执行对应的静态初始化模块。
我们为了方便常常把 验证、准备、解析是三个步骤统称为链接。而链接就是类加载过程中的核心步骤:将字节码文件的内容转化为jvm的运行时环境中可以直接用的过程。
这个过程通常是由虚拟机来完成,我们无法过多干预。但是对于如何进行加载,也就是步骤1中的how,我们可以通过对类加载器进行重载来满足很多我们需要,这也是类加载过程中,我们能最多干预的地方。(这一部分由于内容比较大而复杂我会在后边的文章中记录)
6、使用(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
7、卸载-对jvm中已经存在的class对象进行卸载。
关于类class对象的卸载条件:
1、该class的任何实例对象都已经被回收了。
2、加载该class文件的classloader也已经被回收了
3、该class文件也不存在任何地方持有他的引用。
也就是说,从目前的角度来看,jvm基本不会再使用到该class文件。此时就可以卸载掉该class对象了
这里要注意:
1、类的加载前会先加载父类,只有当直接父类加载完毕后,才会挤在当前类。而直接父类的加载又要依托于直接父类的直接父类。依次类推,直至所有类加载完毕。
2、类的加载过程中各步骤的开始是依照前文中的描述。但是为保证更高的效率,各步骤在执行阶段则可能会互相交错执行,如一边加载一边链接。同时解析阶段为了支持jvm的动态绑定(运行时绑定)原因,解析可能会在初始化步骤开始后才开始。
3、类初始化的顺序
会先依次执行静态变量的初始化,接着执行静态块的初始化。(如果是构造实例的话,则会接着初始化变量,初始化块,构造器)