JVM探索之路之Class文件结构解析(三):访问修饰符、类索引、父类索引与接口索引集合

 

JVM 学习笔记目录:

JVM探索之路之Class文件结构解析(一):Class文件的格式与定义 

JVM探索之路之Class文件结构解析(二):常量池  

 

JVM探索之路之Class文件结构解析(三)

先将分析需要的资源信息列出来:

 case:

package com.beliefbetrayal.clazz;

public class ClassFileTest {

private int m;

public int getM() {
return m;
}

public void setM(int m) {
this.m = m;
}
}

Class文件结构表:

javap工具分析Class文件信息常量池部分:

在上一次分析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类型的之类的信息。具体的标志位及标志的含义如下表:

访问标志 
标志名称 标志值 含义
ACC_PUBLIC 0x0001 是否为public类型
ACC_FINAL 0x0010 是否被声明为final,只有类可以设置,接口不能设置该标志
ACC_SUPER 0x0020 是否允许使用invokespecial字节码指令(查了一下该命令的作用为"调用超类的构造方法,实例的构造方法,私有方法"),JDK1.2以后的编译器编译出来的class文件该标志都为真
ACC_INTERFACE 0x0200 标识这是一个接口 
ACC_ABSTRACT 0x0400  是否被声明为abstract类型,对于接口和抽象类来说此标志为真,其他类为假
ACC_SYNTHETIC 0x1000  标识这个类并非由用户代码生成
ACC_ANNOTATION 0x2000  标识这是一个注解
ACC_ENUM 0x4000  标识这是一个枚举

  查看"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文件中。

 

个人理解难免疏漏错误,欢迎指正讨论。 

posted @ 2012-02-04 00:53  信仰や欺骗  阅读(1730)  评论(1编辑  收藏  举报