字节码访问标志与字段表详解

在上一次【https://www.cnblogs.com/webor2006/p/9457722.html】对字节码的整体结构有了一个初步认识,回顾一下:

下面再来看另外一个更加直观的表:

其中需要说明的是:

如果接口个数为0的话,那么下面的接口名则不会出现了,其它的字段、方法、附加属性都类似。

还有一个需要说明:

下面以结构体的形式来看一下完整的Java字节码结构,当然啦也就是跟上面的表对应的:

下面再来补一补理论:

Class字节码中有两种数据类型:

  • 字节数据直接量:这是基本的数据类型。共细分为u1、u2、u3、u4四种,分别代表连续的1个字节、2个字节、4个字节、8个字节组成的整体数据。
  • 表(数组):表是由多个基本数据或其它表,依照既定顺序组成的大的数据集合。表是有结构的,它的结构体现在:组成表的成分所在的位置和顺序都是已经严格定义好的。

另外再来回顾一下常量池表:

上面的表中描述了11种数据类型的结构,其实在JDK1.7之后又增加了3种(CONSTANT_MethodHandle_info,CONSTANT_MethodType_info以及CONSTANT_InvokeDynamic_info)。这样一共是14种。

字节码Access_Flag访问标志:

好,在了解了常量池之后,接下来则是访问标志信息了,如下:

访问标志信息包括该Class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明为final。而我们所定义的源代码就知道文件是类而且是public的:

而访问标志对应字节码信息如下表:

其中都是以"ACC"开头的。好,了解了访问标志之后,下面回到咱们的二进制文件中来往下分析,常量池之后两个字节表示访问标志,则数两个字节:

那它到底代表什么访问标志呢,到刚才的那张英文表中去找,发现木有“0x0021”对应的标志,如下:

其实原因是这样的:由于Java的修饰符是多种多样的,并没有穷举了每一种组合,而是每一个访问修饰符定义了一个值,那如果一个类既是public,又是final的,此时就会取这两个修饰符的并集:

0x0011 & 0x0010 = 0x0011,所以在二进制字节码中就会记录“0x0011”,同样的,回到咱们的“0x0021”,通过查找,发现是:

所以0x0021:是0x0020和0x0001的并集,表示ACC_PUBLIC与ACC_SUPER。表示该类是public的并能调用父类的。所以在javap -verbose中能够看到:

紧接着访问标志之后两个字节则是当前类的类名,如下:

所以往后数两个字节:

注意:这是一个索引,指向常量池,所以从常量池中找一下:

紧接着再往后两个字节则是父类类名:

同样也在常量池中去找寻:

紧接着父类名称之后,则是接口信息了:

进一步展开如下:

也就是先数两个字节来看一下接口的数量:

表示当前类没有实现接口,既然接口数为0,则接口名则不会出现了,如下:

字段表:

好,两往下则是字段表信息了,如下:

字段表用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包括方法内部声明的局部变量。

接下来需要了解一下“字段表集合”,这是一个比较复杂的概念,虽说展开字段的信息是这样:

但是变量表是有自己的结构的,就像常量池一看它是cp_info:

它也是有它的结构,所以下面来看一下字段表结构:

其中access_flags代表访问修饰符,占2个字节;name_index代表字段的名称索引,占2个字节;descriptor_index代表描述符的索引,占2个字节;这三个信息就可以完整的描述一个字段的信息;attributes_count:属性个数,可有可无;

用结构体形式可以描述为:

好,回到二进制文件中来分析一下字段信息,先数2个字节来看一下字段的个数:

表示类中有一个字段,接下来得要根据字段表来看一下该字段的具体信息,首先数2个字节表示修饰符信息,如下:

所以往后数两个字节呗:

那它代表什么修饰符呢,上这张表去查一下:

呃~~什么鬼,木有是0x0002的修饰符嘛,其实它是ACC_PRIVATE,只是未列在此表中,对应源代码确实是嘛:

接下来两个字节表示字段名称索引,如下:

那数两个字节呗:

上常量池去查找:

再往后两个字节则是描述符的索引:

数两个字节:

继续上常量池中查找:

接下来两个字节则是属性数量,如下:

两数2个字节:

说明该字段木有属性信息,所以之后的attributes也不可能出现在二进制文件当中了,至此,整个字段信息就分析完了!

原文地址:https://www.cnblogs.com/webor2006/p/9457973.html