一、概述
在开发Java程序的过程中,作为开发者你是否想过我们写的.java代码是如何运行起来的呢?其实这里就涉及到了类的加载流程,即类是如何被加载的。
首先我们用到的开发工具比如idea,写的java代码都是.java结尾的文件,类的加载首先由编译器将这个.java编译成.class字节码文件,然后再进入正式加载的流程,类的加载流程工分为以下三大阶段。
- 加载
- 链接
-验证
-准备
-解析 - 初始化
接下来我们根据这个加载的流程一个一个来讲解。
二、加载
将class文件加载到java虚拟机。
- 通过一个类的全限定名获取定义此类的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
三、验证
验证的目的就在于确保Class文件中包含的信息符合当前虚拟机的要求,保证被加载类的正确性,安全性。
验证包括四种验证:
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
四、准备
为类的static变量分配内存,并设置该变量的默认初始值,即零值。
其中不包含final修饰的static,因为final在编译的时候就会分配了,准备阶段会显式初始化。
不会为实例变量分配和初始化,类变量会分配在方法区中,而实例变量式随着对象一起分配到堆内存。
五、解析
将常量池内的符号引用转换为直接引用。
符号引用:符号引用就是一组符号来描述所引用的目标。
直接引用:直接引用就是直接指向目标的指针,相对偏移量或一个间接定位到目标的句柄。
解析的对象主要包括:
- 类/接口
- 字段
- 类方法
- 接口方法
- 方法类型
- 方法句柄
六、初始化
初始化类变量或静态语句。
初始化阶段就是执行类构造器方法<clinit>()的过程。
此方法是由javac编译器自动收集类中的类变量的赋值动作和静态代码块中的语句合并而来。且按照源文件中定义的顺序执行。
子类的<clinit>()执行前,父类的<clinit>()一定会先执行。