且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

JVM15_类的加载、链接、初始化、卸载、主动使用、被动使用(二)

更新时间:2022-06-26 08:18:21

③. 过程二:链接(Linking)


①. 验证:确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性


目的是确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全


主要包括四种验证:文件格式验证,元数据验证,字节码验证,符号引用验证


格式检查:是否以魔术oxCAFEBABE开头,主版本和副版本是否在当前Java虚拟机的支持范围


内,数据中每一项是否都拥有正确的长度等


JVM15_类的加载、链接、初始化、卸载、主动使用、被动使用(二)


②. 准备(静态变量,不能是常量)


为类变量分配内存并且设置该类变量的默认初始化值


这里不包含用final修饰的static,因为final在编译的时候就会分配了,准备阶段会显式赋值

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


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


JVM15_类的加载、链接、初始化、卸载、主动使用、被动使用(二)


③. 解析:将常量池中的符号引号转换为直接引用的过程(简言之,将类、接口、字段和方法的符号引用转为直接引用)


虚拟机在加载Class文件时才会进行动态链接,也就是说,Class文件中不会保存各个方法和字段的最终内存布局信息,因此,这些字段和方法的符号引用不经过转换是无法直接被虚拟机使用的。当虚拟机运行起来时,需要从常量池中获得对应的符号引用,再在类加载过程中(初始化阶段)将其替换直接引用,并翻译到具体的内存地址中


符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到了内存中


直接引用:直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是与虚拟机实现的内存布局相关的,同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那说明引用的目标必定已经存在于内存之中了。


不过Java虚拟机规范并没有明确要求解析阶段一定要按照顺序执行。在HotSpot VM中,加载、验证、准备和初始化会按照顺序有条不紊地执行,但链接阶段中的解析操作往往会伴随着JVM在执行完初始化之后再执行


符号引号有:类和接口的权限定名、字段的名称和描述符、方法的名称和描述符


解释什么是符号引号和直接引用?


(1). 教室里有个空的位子没坐人,座位上边牌子写着小明的座位(符号引用),后来小明进来坐下去掉牌子(符号引用换成直接引用)


(2). 我们去做菜,看菜谱,步骤都是什么样的(这是符号引号),当我们实际上去做,这个过程是直接引用


(3). 举例:输出操作System.out.println()对应的字节码:


invokevirtual #24 <java/io/PrintStream.println>


JVM15_类的加载、链接、初始化、卸载、主动使用、被动使用(二)


以方法为例,Java虚拟机为每个类都准备了一张方法表,将其所有的方法都列在表中,当需要调用一个类的方法的时候,只要知道这个方法在方法表中的偏移量就可以直接调用该方法。通过解析操作,符号引用就可以转变为目标方法在类中方法表中的位置,从而使得方法被成功调用。