JVM将我们写的代码文本文件编译成了class字节码文件,而将字节码文件加载到内存当中的这个过程叫做类加载。
下图表现了一个类的生命周期
其中类加载到内存中有加载、连接、初始化这三步;而连接部分又包含了验证、准备、解析这三步,其中解析阶段有可能在初始化阶段之后再执行(后期绑定)。类加载的步骤除了解析阶段可能在初始化之后完成,其他的步骤都是按顺序完成的。
加载
加载要和类加载区分开,类加载是指加载、连接、初始化三个阶段,加载只是其中的第一阶段。
加载要做的事情是,将class字节码转化为运行时数据结构存储在方法区中,并在堆中生成一个java.lang.Class类型的对象以便用户调用,要注意在堆中生成的是Class类型的对象,而不是该类的对象。
连接
1.验证
对class静态结构进行语法语义上的分析,以保证其不会产生危害虚拟机的行为。
验证阶段具体指的是元数据和字节码的验证,但在整个类加载的过程中都有验证的环节,包括加载阶段会对文件格式进行验证,验证阶段对元数据和字节码验证,解析阶段对符号引用验证。
2.准备
通过验证阶段验证,就会进入准备阶段。这一阶段主要是为静态变量赋一个默认值。
3.解析
将常量池中的符号引用替换为直接引用,将其他类的符号引用替换为直接引用,注意这里如果其他类还没有进行类加载,就会触发该类的类加载机制。
这里进行了类调用,如果类A调用的是B是一个具体的实现类,就称为静态解析;如果上层Java代码使用了多态,B是一个抽象类或者接口,有C和D两个具体实现,A就不知道该调用哪个实现类来完成解析,这种情况下,类加载会先完成初始化阶段,在运行过程中发生了具体调用,才能知道A调用的是哪个实现类,将符号引用替换为直接引用才能完成解析。这就是为什么说解析可能发生在初始化之后。
初始化
本阶段就是完成成员变量和静态变量的赋值动作和完成静态代码块,如果类文件中显示的使用了new指令,才会调用构造函数去实例化一个对象。