1、类加载的生命周期
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:
(1)加载
(2)验证
(3)准备
(4)解析
(5)初始化
(6)使用
(7)卸载
一共7个阶段。其中验证、准备、解析这3个阶段统称为连接。
这类加载的7个阶段顺序流程:
加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的。类的加载过程中必须按照这种顺序按部就班地开始,而解析阶段则是不一定的,它在某些情况下可以在初始化阶段之后再开始,这是为了支持JAVA语言的运行时绑定(也称为动态绑定和晚期绑定)。
初始化的时候执行一些静态代码块,静态变量等。
2、类加载的过程
包括:加载、连接(验证、准备、解析)、初始化。
(1)加载:“加载”是“类加载”的过程的一个阶段,在加载阶段虚拟机需要完成3件事:
a、通过一个类的全限定名来获取定义此类的二进制字节流。
b、将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构。
c、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
(2)验证:验证是连接阶段的第一步,这个阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机的自身安全。
(3)准备:准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。首先,这时候进行内存分配的仅包括类变量(被static修饰的变量)。而不包括实例变量。实例变量将会在对象实例化时随着对象一起分配在java堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:
public static int value = 112;
那变量value值在准备阶段过后的初始值为0而不是112。因为这时候尚未开始执行任何JAVA方法。而把value赋值为112的public static 指令是程序编译后,存放于构造器<cinit>()方法 之中,所以把value赋值为112的动作将在初始化阶段才会执行。
对于那种不是“通常情况”,而是“特殊情况”的变量:
public static int value = 123;
编译的时候Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为123,。
(4)解析:解析阶段是将虚拟机常量池内的符号引用替换为直接引用的过程。
(5)初始化:类初始化是类加载过程的最后一步,在这个阶段,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码(或者说字节码)。在准备阶段,变量已经赋值过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化变量和其他资源,或者可以从另外一个角度来表达,初始化阶段就是执行类构造器<cinti>()方法的过程。