Java虚拟机JVM学习03 连接过程:验证、准备、解析
类被加载后,就进入连接阶段。
连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去。
连接阶段三个步骤:验证、准备和解析。
类的验证
类的验证内容:
1.类文件的结构检查
确保类文件遵从Java类文件的固定格式。
2.语义检查
确保类本身符合Java语言的语法规定,比如验证final类型的类没有子类,以及final类型的方法没有被覆盖。
注意,语义检查的错误在编译器编译阶段就会通不过,但是如果有程序员通过非编译的手段生成了类文件,其中有可能会含有语义错误,此时的语义检查主要是防止这种没有编译而生成的class文件引入的错误。
3.字节码验证
确保字节码流可以被Java虚拟机安全地执行。
字节码流代表Java方法(包括静态方法和实例方法),它是由被称作操作码的单字节指令组成的序列,每一个操作码后都跟着一个或多个操作数。
字节码验证步骤会检查每个操作码是否合法,即是否有着合法的操作数。
4.二级制兼容性的验证
确保相互引用的类之间的协调一致。
例如,在Worker类的gotoWork()方法中会调用Car类的run()方法,Java虚拟机在验证Worker类时,会检查在方法区内是否存在Car类的run()方法,假如不存在(当Worker类和Car类的版本不兼容就会出现这种问题),就会抛出NoSuchMethodError错误。
类的准备
在准备阶段,Java虚拟机为类的静态变量分配内存,并设置默认的初始值。
例如对于以下Sample类,在准备阶段,将为int类型的静态变量a分配4个字节的内存空间,并且赋予默认值0,为long类型的静态变量b分配8个字节的内存空间,并且赋予默认值0。
package com.mengdd.classloader; public class Sample { private static int a = 1;
private static long b; static {
b = 2;
}
}
类的解析
在解析阶段,Java虚拟机会把类的二级制数据中的符号引用替换为直接引用。
例如在Worker类的gotoWork()方法中会引用Car类的run()方法。
public void gotoWork() { car.run();// 这段代码在Worker类的二进制数据中表示为符号引用 }
在Worker类的二进制数据中,包含了一个对Car类的run()方法的符号引用,它由run()方法的全名和相关描述符组成。
在解析阶段,Java虚拟机会把这个符号引用替换为一个指针,该指针指向Car类的run()方法在方法区内的内存位置,这个指针就是直接引用。
参考资料
圣思园张龙老师Java SE系列视频教程。