在JVM的链接阶段主要是分成了验证、准备、解析三个过程,现逐一进行解释
声明,像前文说的一样,这五个过程并不是严格按照介绍的顺序串行执行的
验证
在验证阶段主要可以分为3个验证方面,用于不同阶段的验证
- 格式验证,这个格式验证主要是完成一些必要信息的检查,比如cafebabe,版本号的检查,当前的JVM版本是否.class文件的版本号对应的文件以及一些很简单的验证例如常量池个数为n,实际到底是不是n-1个呢,等一系列可以直观检查出来的问题。这个阶段其实就发生在加载的后面,属于第一步安全验证,如果这一步不通过的话,后面没有执行的意义!
- 语法检查,字节码检查,这两项检查都是对于“语法”层面的检查,一个是检查java代码一个是检查字节码,这个Java代码会检查地比较细致,可以检查到具体的语法规范,例如抽象方法实现了吗、接口的方法被该类完全实现了吗等。但是字节码就不会检查的很细致,只会检查在某些位置是否有正确的数值类型,例如应该给long的位置给了int 这个会检查出来,其余的检查不出来。
- 引用检查,这个检查其实应该是处于解析环节的检查因为要实际检查一下对应的直接引用是否存在,主要是检查引用的对象是否存在,例如当前被调用的方法是否真实存在。
准备
在准备阶段主要是完成了类变量默认值的赋值过程,需要强调的一点是 变量,例如int类型的变量赋值为0,double类型的变量赋值为0.0,引用类型的变量赋值为null。但是对于常量来说的话,这个阶段其实就是完成了常量的赋值,因为毕竟是常量,只能赋值一次,不许下一次再改变了。但是被final 修饰的类变量不一定在准备阶段全部赋初始值,被赋值的final类变量的值是字面量的时候才会在准备阶段完成赋值,例如10,“qwer”,这种字面量的参数会在准备阶段完成赋值。
解析
在这个阶段主要是完成常量池的符号引用转为直接引用,其实就是把一堆字面量,单纯的字面量转换成可以供JVM调用的数据结构,其实就是把这个方法或者属性的内存地址实际转化过去,而不仅仅是单纯的符号。
在JVM中每一个类都会有一张方法表和一张属性表(很显然地,总不能随便存储一类相同的信息)因此,只要把常量池的符号解析成对应内存实际的偏移量就可以了,简单来说就是把字面东西具体化。