类的加载过程(类的生命周期)详解 (2)

如果数组的元素类型是引用类型,数组类的可访问性就由元素类型的可访问性决定。否则数组类的可访问性将被缺省定义为public。

17.3. 过程二:Linking(链接)阶段 17.3.1. 环节1:链接阶段之Verification(验证)

当类加载到系统后,就开始链接操作,验证是链接操作的第一步。

目的:保证加载类的字节码合法合理符合规范

验证的步骤比较复杂,实际要验证的项目也很繁多,大体上Java虚拟机需要做以下检查,如图所示。

类的加载过程(类的生命周期)详解

整体说明:

验证的内容则涵盖了类数据信息的格式验证、语义检查、字节码验证,以及符号引用验证等。

格式验证会和加载阶段一起进行,验证通过之后,类加载器才会成功将类的二进制数据信息加载到方法区中。

格式验证之外的操作将会在方法区进行

链接阶段的验证虽然拖慢了加载速度,但是它避免了在字节码运行时还需要进行各种检查。(磨刀不误砍柴工)

具体说明:

格式验证:是否以魔数0XCAFEBABE开头,主版本和副版本号是否在当前Java虚拟机的支持范围内,数据中每一个项是否都拥有正确的长度等。

语义检查:Java虚拟机会进行字节码的语义检查,但凡在语义上不符合规范的,虚拟机也不会给予验证通过。比如:

是否所有的类都有父类的存在(在Java里,除了object外,其他类都应该有父类)

是否一些被定义为final的方法或者类被重写或继承了

非抽象类是否实现了所有抽象方法或者接口方法

字节码验证:Java虚拟机还会进行字节码验证,字节码验证也是最为复杂的一个过程,

它试图通过对字节码流的分析,判断字节码是否可以被正确地执行。比如:

在字节码的执行过程中,是否会跳转到一条不存在的指令

函数的调用是否传递了正确类型的参数

变量的赋值是不是给了正确的数据类型等

栈映射帧(StackMapTable)就是在这个阶段,用于检测在特定的字节码处,其局部变量表和操作数栈是否有着正确的数据类型。但遗憾的是,100%准确地判断一段字节码是否可以被安全执行是无法实现的,因此,该过程只是尽可能地检查出可以预知的明显的问题。如果在这个阶段无法通过检查,虚拟机也不会正确装载这个类。但是,如果通过了这个阶段的检查,也不能说明这个类是完全没有问题的。

符号引用的验证:校验器还将进符号引用的验证。Class文件在其常量池会通过字符串记录自己将要使用的其他类或者方法。因此,在验证阶段,虚拟机就会验证类或者方法确实存在,并且当前类有权限访问这些数据,如果一个需要使用类无法在系统中找到,则会抛出NoClassDefFoundError,如果一个方法无法被找到,则会抛出NoSuchMethodError。此阶段在解析环节才会执行。

17.3.2. 环节2:链接阶段之Preparation(准备)

准备阶段:为类变量分配内存,并进行默认初始化

当一个类验证通过时,虚拟机就会进入准备阶段。在这个阶段,虚拟机就会为这个类分配相应的内存空间,并设置默认初始值。Java虚拟机为各类型变量默认的初始值如表所示。

类型 默认初始值
byte   (byte)0  
short   (short)0  
int   0  
long   0L  
float   0.0f  
double   0.0  
char   \u0000  
boolean   false  
reference   null  

Java并不支持boolean类型,对于boolean类型,内部实现是int,由于int的默认值是0,故对应的,boolean的默认值就是false。

注意

这里不包括基本数据类型使用static final修饰的情况,因为final在编译的时候就会分配,准备阶段会显示赋值

注意这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwfyzp.html