attributes_count表示这个字段有几个属性
时间:2021-11-22

fields_count和fields在class文件中。

fields_count描述了当前类中定义的字段的数量。请注意,它包括静态字段,但不包括从父类继承的字段。如果当前的class文件是由接口生成的,那么这里的fields_count描述了界面中定义的字段,我们知道界面中定义的字段默认是静态的。另外需要注意的是,编译器可能会自动生成字段,也就是说,class文件中的字段中定义的字段多。例如,编译器将为内部类添加一个字段,指向外围类对象。

fields_count下面的数据称为fields,可以看作是数组,数组中的每个项目都是field_info。该数组共有field_countfield_info,每个field_info都是对一个字段的描述。下面我们详细讲解field_info的结构。每个field_info的结构如下:

attributes_count表示这个字段有几个属性


(1)access_flags。

access_flags占两个字节,描述字段的访问标志信息。这里就不详细介绍了,下面给出一个表格(这个表格来自虚拟机):

attributes_count表示这个字段有几个属性

(2)name_index。

access_flags下面的两个字节是name_index,指向常量池,描述当前字段的字段名。该索引指向常量池中的constant_utf8_info数据项。存储在这个constant_utf8_info数据项中的字符串是当前字段的字段名。

(3)descriptor_index。

name_index下面的两个字节称为descriptor_index,它也是指向常量池的索引,描述当前字段的描述符。该索引指向常量池中的constant_utf8_info数据项。存储在这个constant_utf8_info数据项中的字符串是当前字段的描述符。

(4)attributes_count和attributes。

descriptor_index以下是attributes_count和attributes。这是对当前字段属性的描述。这里的属性和源文件中的属性不一样。在源文件测量层面,属性是字段的另一个名称。希望读者不要怀疑。读者不应轻视class文件中的属性,这些属性可以描述很多信息。我们将在下面的文章中介绍它。

atttributes_count表示这个字段有几个属性。attributes可以看作是一个数组,数组中的每个项目都是attribute_info,每个attribute_info表示一个属性,数组中有attributes_count个性。filed_info中可以出现三种属性,即constantvalue、deprecated和synthetic。这些属性将在后面的文章中介绍。

我们以代码的形式解释,源代码如下:

package com.bjpowernode.test; 


 


 


public class programer extends person{ 


 


 


 


 private computer computer; 


 


 public programer(computer computer){ 


  this.computer = computer; 


 } 


 


public void dowork(){ 


  computer.calculate(); 


 } 


}

反编译后,常量池中会有以下信息(这里省略了大部分无关信息):

constant pool: 


 


......... 


......... 


 


 #5 = utf8    computer 


 #6 = utf8    lcom/jg/zhang/computer; 


 


......... 


......... 


 



 


 private com.jg.zhang.computer computer; 


 flags: acc_private 


 


......... 


......... 


 


}

从反编译的结果可以看出,源文件定义了一个computer类型的字段computer,它是private。然后常量池中有字段名和描述符。常量池第五项的constant_utf8_info是字段名,第六项的constant_utf8_info是字段的描述符。这里需要注意的是,在反编译programer.class时,由于computer是私有的,需要添加-private选项,否则,虽然常量池中有字段引用信息,但字段信息不会输出,即以下两行不会输出:

private com.bjpowernode.test.computer computer; 


flags: acc_private 

如果在javap中添加private选项,将有上述两行的输出。使用的命令如下:

javap -c -v -private -


classpath . com.bjpowernode.test.programer 

根据反编译的结果,可以给出以下示意图,表明与computer对应的field_info不适合引用常量池(其中常量池在虚线范围内):

methods_count和methods在class文件中。

fields下面的信息是methods_count和methods。methods_count描述了当前类中定义的方法的数量。请注意,它包括静态方法,但不包括从父类继承的方法。如果当前的class文件是由接口生成的,那么这里的methods_count描述了界面中定义的抽象方法的数量,我们知道界面中定义的方法默认是公共的。此外,需要注意的是,编译器在编译过程中可能会向class文件添加额外的方法,即class文件中的方法数量可能超过源文件中用户定义的方法。例如,如果当前类没有定义结构方法,编译器将添加一个无参数的结构函数;如果静态变量定义在当前类或接口中,并使用初始化表达式赋值或定义static静态代码块,编译器将默认添加静态初始化方法。

methods_count下面的数据叫methods,可以看作是数组,数组中的每个项目都是method_info。这个数组有methods_countmethod_info,每个method_info都是对一种方法的描述。下面我们详细讲解method_info的结构。每个method_info的结构如下,与field_info的结构几乎相同:

attributes_count表示这个字段有几个属性

(1)access_flags。

access_flags占两个字节,描述方法访问标志信息。这里就不详细介绍了,下面给出一个表格(这个表格来自虚拟机):

attributes_count表示这个字段有几个属性

(2)name_index。

access_flags下的两个字节是name_index,指向常量池,描述当前方法的方法名。该索引指向常量池中的constant_utf8_info数据项。存储在这个constant_utf8_info数据项中的字符串是当前方法的方法名。

(3)descriptor_index。

name_index下面的两个字节称为descriptor_index,它也是指向常量池的索引,描述当前方法的描述符。该索引指向常量池中的constant_utf8_info数据项。存储在这个constant_utf8_info数据项中的字符串是当前方法的描述符。

(4)attributes_count和attributes。

descriptor_index以下是attributes_count和attributes。这是对当前方法所具有的属性的描述。这里的属性和源文件中的属性不一样。在源文件测量层面,属性是字段的另一个名称。希望读者不要怀疑。读者不应轻视class文件中的属性,这些属性可以描述很多信息。我们将在下面的文章中介绍它。

atttributes_count表示这个字段有几个属性。attributes可以看作是一个数组,数组中的每个项目都是attribute_info,每个attribute_info表示一个属性,数组中有attributes_count个性。method_info中可以出现三种属性,即code、deprecated、exceptions和synthetic。在这些属性中,尤其是code和exceptions非常重要。这两个属性在class文件中完整描述一种方法中起着至关重要的作用。code属性中存储方法的字节面指令和exceptions属性是方法声明中抛出的异常描述。这两个属性和其他属性将在下一篇文章中详细介绍。请注意。

介绍了每个method_info的结构后,我们用代码来解释或使用上述源代码:

package com.jg.zhang; 


 


public class programer extends person{ 


 


  


 private computer computer; 


  


 public programer(computer computer){ 


  this.computer = computer; 


 } 


  


 public void dowork(){ 


  computer.calculate(); 


 } 


反编译后,常量池中会有以下信息(这里省略了大部分无关信息):

constant pool: 


 


......... 


 


 #7 = utf8    <init> 


 #8 = utf8    (lcom/jg/zhang/computer;)v 


 


......... 


 


 #12 = utf8    ()v 


 


......... 


 


 #19 = utf8    dowork 


 



 


......... 


 


 public com.jg.zhang.programer(com.jg.zhang.computer); 


 flags: acc_public 


 


......... 


 


 public void dowork(); 


 flags: acc_public 


 


......... 


}

从反编译结果可以看出,这类方法定义了两种,一种是结构方法,另一种是dowork方法,都是public。这两种方法的描述信息都存储在常量池中。第七项constant_utf8_info是构造方法的方法名,第八项constant_utf8_info是构造方法的方法描述符,第19项constant_utf8_info是dowork方法的方法名,第12项constant_utf8_info是dowork方法的方法描述符。

根据常量池中的信息,可以得到以下示意图,解释了class文件中的method_info是如何引用常量池中的数据项来描述当前类中定义的方法的。图中虚线范围表示常量池所在区域:

总结

到目前为止,我们已经介绍了class文件中的fields和methods。

fields是对当前类中定义的字段的描述,每个字段用field_info表示,fields中有field_count_info。

methods是对当前类别或接口中声明的方法的描述,每种方法用method_info表示,methods中有methods_countmethod_info。