Java@深入理解Java虚拟机:类加载机制( 二 )


3、准备正式为类中定义的变量(即静态变量)分配内存并设置类变量初始值的阶段 。
4、解析Java虚拟机将常量池内的符号引用替换为直接引用的过程 。
符号引用:符号引用以一组符号来描述所引用的目标 , 符号可以是任何形式的字面量 , 只要使用时能无歧义地定位到目标即可 。
直接引用:直接引用是可以指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄 。
解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符进行 。

  1. 类或接口的解析(类:D , 符号引用:N , 类或接口的直接应用:C)
    1. 如果C不是一个数组类型 , 那虚拟机将会把代表N的全部限定名传递给D的类加载器区加载这个类C 。 在加载过程中 , 由于元数据验证、字节码验证的需要 , 又可能触发其他相关类的加载动作 , 例如加载这个类的父类或实现的接口 。 一旦这个加载过程出现了任何异常 , 解析过程就将宣告失败 。
    2. 如果C是一个数组类型 , 并且数组的元素类型为对象 , 也就是N的描述符是类似\"[Ljava/lang/Integer\"的形式 , 那将会按照第一点的规则加载数组元素类型 。 如果N的描述符如前面所假设的形式 , 需要加载的元素类型就是\"java.lang.Integer\" , 接着由虚拟机生成一个代表该数组维度和元素的数组对象 。
    3. 如果上面两步没有出现任何异常 , 那么C在虚拟机中实际上已经成为一个有限的类或接口了 , 但在解析完成前还要进行符号引用验证 , 确认D是否具有对C的访问权限 。 如果发现不具备访问权限 , 将抛出java.lang.IllegalAccessError异常 。
  1. 字段解析
    1. 如果C本身就包含了简单名称和字段描述符都与目标想匹配的字段 , 则返回这个字段的直接引用 , 查找结束
    2. 否则 , 如果在C中实现了接口 , 将会按照继承关系从下往上递归搜索各个接口和它的父接口 , 如果接口中包含了简单名称和字段描述都与目标相匹配的字段 , 则返回这个字段的直接引用 , 查找结束 。
    3. 否则 , 如果C不是java.lang.Object的话 , 将会按照继承关系从下往上递归搜索器父类 , 如果在父类中包含了简单名称和字段描述符都与目标想匹配的字段 , 则返回这个字段的直接引用 , 查找结束 。
    4. 否则 , 查找失败 , 抛出java.lang.NoSuchFieldError异常 。
  1. 方法解析
    1. 由于Class文件格式中类的方法和接口的方法符号引用的常量类型定义是分开的 , 如果在类的方法表中发现class_index中索引的C是个接口的话 , 那就直接抛出java.lang.IncompatibleClassChangeError异常 。


      推荐阅读