Java类的加载过程主要分为三大步:Java虚拟机动态加载、链接和初始化类和接口。加载是找到具有特定名称的类或接口类型的二进制表示,并从该二进制表示创建类或接口的过程。链接是获取类或接口并将其组合到Java虚拟机的运行时状态以便执行的过程。类或接口的初始化包括执行类或接口的初始化方法<clinit>
除此之外,下面几种情形需要特别指出:
对于一个final类型的静态变量,如果该变量的值在编译时就可以确定下来,那么这个变量相当于“宏变量”。Java编译器会在编译时直接把这个变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类的初始化。反之,如果final类型的静态Field的值不能在编译时确定下来,则必须等到运行时才可以确定该变量的值,如果通过该类来访问它的静态变量,则会导致该类被初始化。
类加载过程
Loading(加载)
这个过程主要是通过一个类的全限定名来获取该类的二进制字节流,将这个字节流的静态存储结构转化为方法区运行时数据结构,在内存堆中生成一个代表该类的java.lang.Class对象,作为该类数据的访问入口。
java的加载机制是懒加载,在需要的时候才会去加载,类加载时机如下:
1、创建类的实例,也就是new一个对象
2、访问某个类或接口的静态变量,或者对该静态变量赋值
3、调用类的静态方法
4、反射Class.forName
5、初始化一个类的子类(会首先初始化子类的父类)
6、JVM启动时标明的启动类,即文件名和类名相同的那个类
Linking(链接)
1、Verification(验证)
验证是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,不会威胁到jvm的安全, 验证主要包括以下几个方面的验证:
- 文件格式的验证,验证字节流是否符合Class文件的规范,是否能被当前版本的虚拟机处理
- 元数据验证,对字节码描述的信息进行语义分析,确保符合java语言规范
- 字节码验证 通过数据流和控制流分析,确定语义是合法的,符合逻辑的
- 符号引用验证 这个校验在解析阶段发生
2、Preparation(准备)
静态成员变量赋默认值
3、Resolution(解析)
将类的二进制数据中的符号引用替换成直接引用。说明一下:符号引用:符号引用是以一组符号来描述所引用的目标,符号可以是任何的字面形式的字面量,只要不会出现冲突能够定位到就行。布局和内存无关。直接引用:是指向目标的指针,偏移量或者能够直接定位的句柄。该引用是和内存中的布局有关的,并且一定加载进来的。
initiializing(初始化)
为类的静态变量赋值,然后执行类的初始化(static)语句。初始化的详细过程:
1、如果类还没有被加载和链接(即没有执行前两个过程),那就先进行加载和初始化;
2、如果类存在父类,并且父类还没有初始化,那就先初始化直接父类;
3、如果类中存在初始化语句,顺序执行初始化语句。