类加载机制-解析

最近看《深入理解java虚拟机》,对类方法解析的第四条不是很明白,后查百度得文一篇,终于弄明白了。在此转文:

http://chenjingbo.iteye.com/blog/1873948


解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程.这里需要注意三个点,第一是”常量池”,也就是是处理常量池信息的,第二个和第三个点一起说就是”直接引用”和”符号引用”.其实这两个概念很好理解.




看上图的常量池,有”//”注释的就是符号引用常量.它在常量池中的信息是通过一个引用值来标识的.其他可以直接获取到的值,它其实是直接指向目标的指针,便宜了或者句柄.

解析这个步骤做的事情通俗一点说,就是把”//”后面的数据拿到.

解析动作主要针对类或接口,字段,类方法,接口方法四类符号引用进行.至于NameAndType类型的常量,撒迦是这么说的



下面分别对应于四种引用解析过程.

ps :下面的解析过程都可以看到它会到父类,父接口中去找对应的直接引用.其实很好理解:我们在某个方法中是可以直接引用父类或者父接口的常量信息的.
类或接口的解析

这个对应于CONSTANT_Class_info.也就是替换类或接口的..整个解析步骤入下

(1) 如果该引用对应的类不是数组,则会加载对应的类.当然在这个过程中有可能触发其他类的加载(比如父类的加载)

(2) 如果该引用对应为一个数组,那么会先按照(1)加载对应数组中的对象,然后由虚拟机生成一个代表此数组维度和元素的数组对象.

(3) 如果(1)和(2)都没有异常,最后就进行符号引用验证.确定该常量池所对应的类是否有权限访问这个类.如果没有权限,则抛出java.lang.IllegalAccessError
字段解析

这个对应为CONSTANT_Fieldref_info .看下之前在常量池的文档里对CONSTANT_Fieldref_info的描述
写道
CONSTANT_Fieldref_info {
u1 tag; ##值为9
u2 class_index; ##指向字段的类或者接口描述符的索引值
u2 name_and_type_index; ## 指向字段描述符的索引值
}

可以看到CONSTANT_Fieldref_info的第二位描述的是这个字段所属的类或者接口的符号引用,所以说,在进行字段解析的时候,会先解析这个类(或者接口)的符号引用.当解析成功以后,才会开始下面的步骤(假设字段所属的类为C)

(1) 如果C本身就包含了这个字段对应的简单名称和字段描述符都与目标相匹配的字段,则直接返回

(2)如果C实现了接口,则递归到被实现的接口和父接口里面找,找到这个字段对应的简单名称和字段描述符都与目标相匹配的字段,则返回.

(3) 递归到C的父类继续找, ,找到这个字段对应的简单名称和字段描述符都与目标相匹配的字段,则返回.注意,这里会一直递归到Object类.

(4) 如果上面3条都找不到的话,则抛出java.lang.NoSuchFieldError.



虽然虚拟机规定在解析Field的时候是按照这个顺序,但是编译器会比上面的规范更加严格.比如在同一个类型的同名字段同时出现接口或者起父类中的时候,编译器会拒绝编译.

当然,在最后还是会检查权限问题,如果无权限,则抛出java.lang.IllegalAccessError


类方法解析

这个步骤对应的是CONSTANT_Methodref_info.它也和字段解析一下,需要先解析出类方法表中的class_index项.这个解析成功以后才会继续如下步骤(假设字段所属的类为C):

(1)这一条需要待定,我还有疑惑.这一步的检查大概是这样的,它会检查对应的C是否C是一个接口,如果是接口,则抛出java.lang.IncompatibleClassChangeError

(2) 如果通过了第一步,那么再到C中找是否有简单名称和描述符都与目标相匹配的方法.如果有则直接返回.

(3)到C的父类中递归查找是否有简单名称和描述符都与目标相匹配的方法.如果有则直接返回(一直递归到Object类).

(4)在实现C的接口列表及其父接口中递归查找是否有简单名称和描述符都与目标相匹配的方法.如果有则说明是抽象类.这个时候抛出java.lang.AbstractMethodError.这个需要这么理解,如果是普通的类去实现某一个接口的方法的话,那么它肯定在第(2)步已经直接返回.如果能执行到第(4)步,则说明C本身的常量池中并没有对应的直接引用.那么只能是说明这个方法是抽象方法.包含抽象方法的类必定是抽象类,所以这里有个结论就是C是抽象类.

(5)如果执行到这里,则抛出java.lang.NoSuchMethodError

当然,在最后还是会检查权限问题,如果无权限,则抛出java.lang.IllegalAccessError

注意,字段解析是先解析父接口,然后再解析父类,而方法解析是先解析父类,再解析父接口.
接口方法解析

这个对应的是CONSTANT_InterfaceMethodref_info.注意这里的方法是接口中的方法,这个在常量池那里已经说明.所以它对应的类肯定是一个接口. 它也是需要先解析接口方法表中class_index项中的索引的方法所属的类或者接口的符号引用.如果解析成功,才会指向如下步骤(继续用C表示这个接口)

(1) C是否C是一个类(而不是一个接口),则抛出java.lang.IncompatibleClassChangeError

(2)在C中查找是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用,

(3) 在接口C的父接口中递归查找是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用,

(4)否则,方法解析失败,抛出java.lang.NoSuchMethodError.

由于接口中的方法都是public的,所以不会有访问权限问题.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值