准备
正式为类中定义的变量(静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段。
注意:
这些变量都应当在方法区中分配,但是方法区只是一个逻辑区域。(1)<JDK7,HotSpot使用永久代来实现方法区;(2)>JDK8,类变量会随着Class对象一起存放在Java堆中。
在这个时候进行内存分配的仅包括类变量,而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中。
public static int value=123;
在准备阶段初始值为0而不是123,由于尚未开始执行任何Java方法,而把value赋值为123的putstatic指令是程序被编译后。
public static final int value=123;
编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为123.
解析
解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程。
符号引用:以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可。【引用的目标并不一定是已经加载到虚拟机内存当中的内容】
直接引用:可以直接指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄。【直接与虚拟机内存布局相关,有了直接引用,那目标必定在虚拟机内存中】
-
类或接口的解析
如果把一个从未解析过的符号引用N解析为一个类或接口C的直接引用,那虚拟机完成整个解析的过程包括以下3个步骤:
–C不是数组类型,把代表N的全限定名传递给D的类加载器去加载这个类C。
–C是一个数组类型,N的描述符是类似“[Ljava/lang/Integer”的形式,那将会按照第一点的规则加载数组元素类型。
–如果上面两步没有出现任何异常,那么C在虚拟机中实际已经成为一个有效的类或接口了,在解析完成前还要进行符号引用验证,确认D是否具备对C的访问权限。 -
字段解析
要解析一个未被解析过的字段符号引用,首先将会对字段表内的class_index项中索引的CONSTANT_Class_info引用进行解析,也就是字段所属的类或接口的符号引用。
《Java虚拟机规范》要求按照如下步骤对C进行后续字段搜索:
–C包含了简单名称或字段描述符都与目标相匹配的字段,直接返回这个字段的直接引用。
–在C中实现了接口,按照继承关系从下往上递归搜索各个接口和它的父接口,如果接口中包含了简单名称和字段描述符都与目标相匹配的字段,则返回这个字段的直接引用。
–C不是java.lang.Object的话,按照继承关系从下往上递归搜索其父类,父类中包括简单名称和字段描述符,则直接返回这个字段的直接引用。
–否则,查找失败,抛出java.lang.NoSuchFieldError异常。 -
方法解析
方法解析的第一个步骤与字段解析一样,先解析出方法表的class_index项中索引的方法所属的类或接口的引用。
–Class文件格式中类中的方法和接口的方法符号引用的常量类型定义是分开的。发现class_index中索引的C是个接口的话,那就直接抛出java.lang.IncompatibleClassChangeError异常。
–通过第一步,在类C中查找是否有简单名称和描述符都与目标匹配的方法,有则直接返回,查找结束。
–否则,在类C的父类中递归查找是否有简单名称和描述符都与目标相匹配的方法,有则返回,查找结束。
–否则,在类C实现的接口列表及它们的父接口之中递归查找是否有简单名称和描述都与目标相匹配的方法,如果存在匹配的方法,说明类C是一个抽象类,这时候查找结束,抛出Java.lang.AbstractMethodError。
–否则,宣告方法查找失败,抛出java.lang.NoSuchMethodError。 -
接口方法解析
接口方法也是需要先解析接口方法表的class_index项中索引的方法所属的类或接口的符号引用,如果解析成功,依然用C表示这个接口。
–与类的方法解析相反,如果在接口方法表中发现class_index中的索引C是个类而不是一个接口,那么直接抛出java.lang.IncompatibleClassChangeError异常。
–否则,在接口C中查找是否有简单名称和描述符都与目标相匹配的方法。有则返回这个方法的引用,查找结束。
–否则,在接口C的父接口中递归查找,直到java.lang.Object类(包括Object类中的方法)为止,看是否有简单名称和描述符都与目标相匹配的方法。有则直接返回,查找结束。
–由于java接口允许多重继承,如果C的不同父接口中存在多个简单名称和描述符都与目标相匹配的方法,那将会从这多个方法中返回其中一个并结束查找。
–否则,宣告方法查找失败,抛出java.lang.NoSuchMethodError异常。