JVM探索之路之Class文件结构解析(三):访问修饰符、类索引、父类索引与接口索引集合
JVM 学习笔记目录:
JVM探索之路之Class文件结构解析(一):Class文件的格式与定义
JVM探索之路之Class文件结构解析(三)
先将分析需要的资源信息列出来:
package com.beliefbetrayal.clazz;
public class ClassFileTest {
private int m;
public int getM() {
return m;
}
public void setM(int m) {
this.m = m;
}
}
在上一次分析Class文件的博文中已经详细分析了如何手工解析Class文件中的constant_pool信息,现在接着分析Class文件结构中紧随constan_pool的访问标示符(access_flag)。使用WinHex打开ClassFileTest.class文件,并找到contant_pool结束的位置:
查看"javap工具分析Class文件信息常量池部分"找到最后一个常量,其值为"ClassFileTest.java",注意";"并不是Class文件中数据,在WinHex中找到它对应的值,以确定常量池结束的位置。查看"Class文件结构表",可知紧随constan_pool的是2个字节代表的访问标志,这个标志的作用是用于识别一些类或者接口层次的访问信息,例如:这个Class是类还是接口,是否定义为public,是否定义为abstract,如果是类的话,是否被定义为final类型的之类的信息。具体的标志位及标志的含义如下表:
查看"ClassFileTest.java"源代码,可以看到该类被声明为"public"的,JDK1.6编译出来的文件,JVM中没有使用标志为一律为0,所以只有ACC_PUBLIC与ACC_SUPER标志位不为0,因此它access_flag的值为0x0001|0x0020=0x0021("|"布尔或操作符),这里省略了其他6个标志的计算,因为"|"操作符,只有全为0才为0,所以虽然要计算8个标志为的值,但是可以简化为2个。
可以看到上图,紧接着2个字节的值为"0x0021",与我们计算的一致。access_flag分析完后,紧接着access_flag的是2个字节的类索引(this_class),2个字节的父类索引(super_class)和一组2个字节的数据集合接口索引(interfaces)。Class文件中就是由这三项数据确定这个类的继承关系。其中类索引this_class用于确定这个类的全限定名:
如图,类索引this_class的值为"0x0001",它是一个指向常量池的索引,"0x0001"转化为十进制为1,表示常量池第一个常量,查看"javap工具分析Class文件信息常量池部分"找到第一项常量,它指向第二项常量,找到第二项常量,可以看到"com/beliefbetrayal/clazz/ClassFileTest"的字符串,这不正是我们定义的类的全限定名。分析完类索引,接着分析父类索引(super_class),众所周知Java语言不允许多继承,索引父类只有一个,除了java.lang.Object类,其他类都有父类:
如图,父类索引super_class值为"0x0003",转换为十进制为3,它与类索引一项指向常量,查看"javap工具分析Class文件信息常量池部分"找到第三个常量,第三个常量又指向第四个常量,看到了"java.lang.Object"的字符串值,这就是为什么显示extends java.lang.Object也会继承他的原因,编译器干的好事^_^。接着分析接口索引(interfaces),查看"Class文件结构表",可以看到它有一个2个字节"interfaces_count"前置计数器,用于计算该类实现了多少个接口,而"interfaces"接口索引用于表式类实现的接口,按照implement语句从左到右排列到接口索引集合中:
因为"ClassFileTest.java"源代码并没有实现任何接口,所以"interfaces_count"前置计数器为0,如图所示它的值如分析的一样"0x0000",因为 "interfaces_count"前置计数器为0,Class文件就不必留空间记录接口索引集合(interfaces),索引接口索引集合(interfaces)信息不会出现在Class文件中。
个人理解难免疏漏错误,欢迎指正讨论。