编辑
一、概述
在接口索引集合后面 的就是字段表集合了。字段表(field_info)用于描述接口或者类中声明的变量。字段包括类级变量以及实例级变量,但是不包括在方法内部声明的局部变量。
编辑
二、字段表集合的构成
1.字段计数器
字段表集合是由很多field_info组成的,所以字段表集合的前两个字节表示有多少个字段,占两个字节,16位。
2.field_info
每个field_info的结构如下表所示:
类型 | 名称 | 数量 |
u2 | access_flags | 1 |
u2 | name_index | 1 |
u2 | descriptor_index | 1 |
u2 | attributes_count | 1 |
attribute_info | attributes | attributes_count |
编辑
3.access_flags
access_flags为字段修饰符,也称字段访问标志。access_flag占2个字节,16位,它与类中的access_flags项目是非常相似的,包括如下类型:
标志名称 | 标志值 | 含义 |
ACC_PUBLIC | 0x00 01 | 字段是否为public |
ACC_PRIVATE | 0x00 02 | 字段是否为private |
ACC_PROTECTED | 0x00 04 | 字段是否为protected |
ACC_STATIC | 0x00 08 | 字段是否为static |
ACC_FINAL | 0x00 10 | 字段是否为final |
ACC_VOLATILE | 0x00 40 | 字段是否为volatile |
ACC_TRANSTENT | 0x00 80 | 字段是否为transient |
ACC_SYNCHETIC | 0x10 00 | 字段是否为由编译器自动产生 |
ACC_ENUM | 0x40 00 | 字段是否为enum |
编辑
某个字段拥有哪些标志符,就是要用访问标识取|操作:
如0x0001|0x0008为0x0009。
4.name_index和descriptor_index
name_index和descriptor_index,是对常量池的引用,name_index指字段的简单名称,descriptor_index指字段描述符。
descriptor_index描述符用来描述字段的数据类型,基本数据类型用一个大写字符来表示,而对象类型则用字符加L加对象名的全限定名来表示。
标志符 | 含义 |
B | 基本数据类型byte |
C | 基本数据类型char |
D | 基本数据类型double |
F | 基本数据类型float |
I | 基本数据类型int |
J | 基本数据类型long |
S | 基本数据类型short |
Z | 基本数据类型boolean |
V | 基本数据类型void |
L | 对象类型 |
对数组类型,每一维将使用一个"["字符来描述.如一个Stirng[][]类型的二维数组,将被记录为:[[Ljava/lang/Stirng,一个整型数组"int []"将被记录为"[I"。
三、实例拆解
定义一个类:
public class HelloWord{ public int i; private Long l; protected String[][] arrs; public Object test(){return null;} }
编辑
javap -verbose HelloWord.class
public class com.csdn.reader.HelloWord minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #3.#21 // java/lang/Object."<init>":()V #2 = Class #22 // com/csdn/reader/HelloWord #3 = Class #23 // java/lang/Object #4 = Utf8 i #5 = Utf8 I #6 = Utf8 l #7 = Utf8 Ljava/lang/Long; #8 = Utf8 arrs #9 = Utf8 [[Ljava/lang/String; #10 = Utf8 <init> #11 = Utf8 ()V #12 = Utf8 Code #13 = Utf8 LineNumberTable #14 = Utf8 LocalVariableTable #15 = Utf8 this #16 = Utf8 Lcom/csdn/reader/HelloWord; #17 = Utf8 test #18 = Utf8 ()Ljava/lang/Object; #19 = Utf8 SourceFile #20 = Utf8 HelloWord.java #21 = NameAndType #10:#11 // "<init>":()V #22 = Utf8 com/csdn/reader/HelloWord #23 = Utf8 java/lang/Object { public int i; descriptor: I flags: ACC_PUBLIC protected java.lang.String[][] arrs; descriptor: [[Ljava/lang/String; flags: ACC_PROTECTED public com.csdn.reader.HelloWord(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/csdn/reader/HelloWord; public java.lang.Object test(); descriptor: ()Ljava/lang/Object; flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aconst_null 1: areturn LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 2 0 this Lcom/csdn/reader/HelloWord; }
编辑
四、总结
字段表集合中不会列出从父类或者父接口中继承而来的字段,但有可能列出原来Java代码中不存在的字段和方法,譬如在内部类中为了保持对外部类的访问性,会自动添加指向外部类实例的字段。
另外,在Java语言中字段是无法重载的,两个字段的数据类型,修饰符不管是否相同,都必须使用不一样的名称,但是对于字节码来讲,如果连个字段的描述符不一致,那字段重名就是合法的。
参考资料: