连接定义:
类被加载后,就进入连接阶段。连接就是将以读入到内存的类的二进制类的数据合并到虚拟机的运行时环境中去。
连接有分为三个阶段:验证、准备、解析
下面我就就先看一下验证。
类的验证
类的验证的内容:
- 类文件的结构检查
确保类文件遵从Java类文件的固定格式
- 语义检查
确保本类本身符合java语言的语法规定,比如验证final类型的类有子类,以及final类型的方法有没有被覆盖。
- 字节码验证
确保字节码流可以被java虚拟机安全的执行。字节码流代表Java方法(包括静态方法和实例方法),它是由被称作操作码的单字节指令组成的序列,每一个操作码后都跟着一个或多个操作数,字节码验证步骤会检查每个操作码是否合法, 即是否有着合法的操作数。
- 二进制兼容性的验证
确保相互引用的类之间协调一致,例如在Worker类的gotoWork()方法中会调用Car类的run()方法,Java虚拟机在验证Worker类时,会检查在方法区内是否存在Car类的run()方法,假如不存在(当Worker类和Car类版本不兼容,就会出现这个问题),会抛出NoSuchMethodError错误。
类的准备、解析:
在准备阶段,java虚拟机为类的静态变量分配内存,并设置默认的初始值。
public class Sample{
private static int a = 1;
private Static long b;
static{
b = 3;
}
}
例如Sample类,
在准备阶段,将为int类型的静态变量a分配4个字节的内存空间,并且赋予默认值0,为long类型的的b分配8个字节的内存空间,并且赋予默认值0;
在解析阶段,java虚拟机会把类的二进制数据中的符号引用替换为直接引用。例如在worker类的gotowork()方法中会引用Car类的run()方法。
public void gotoWork(){
car.run();//这段代码在Worker类的二进制数据中表示为符号引用
}
在Worker类的二进制数据中, 包含了一个对Car类的run()方法的符号引用,它由run()方法的全名和相关描述符组成。在解析阶段,java虚拟机会会把这个符号引用替换为一个指针,该指针指向Car类的run()方法在方法区内的内存位置,这个指针就是直接引用。