上篇必看:实例分析Class字节码文件(一)
四、字段表集合
字段表(field_info)集合用于描述接口或者类中声明的变量。
包括:类级变量 + 实例级变量(不包括局部变量)
注:
① 类级变量 = 类变量 = 静态变量 【static int a;
】 存储在方法区;
②实例级变量 :没有static
修饰符,只能通过实例对象访问;存储在对象中;
描述一个字段包含的方面有:
① 字段的作用域 : public
、private
、protected
② 是实例级变量还是类级变量(是否被static
修饰)
③ 可变性(是否被final
修饰)
④ 并发可见性(是否被volatile
修饰)
⑤ 是否可被序列化(transient
修饰)
⑥ 字段数据类型(基本类型、对象、数组)
⑦ 字段名称
字段表结构如下:
access_flags结构如下:
所以access_flags
应为 0x0002;查阅字节码文件,没问题
name_index : 字段的简单名称,值为对常量的引用
指向第5个常量 : ——> m
descriptor_index : 字段和方法的描述符,值为对常量的引用
指向第6个常量 : ——> I ,看到这个感觉有点问题,每个描述符都代表特殊的含义,如下:
descriptor_index一方面可以描述字段类型,如上表;另一方面还可以描述参数列表(包括数量、类型、顺序)和返回值。
注:
① 对于对象类型:用字符L和对象的全限定名来表示(Ljava/lang/Object
)
② 对于数组:每一个维度用一个“[” 表示
java.lang.String[][]-->[[Ljava/lang/String
int[]-->[I
③ 用来描述方法时,按照参数列表,然后返回值的顺序描述,参数列表按照参数的严格顺序放在一组小括号“()”之内
void inc()--->()V
int indexOf(char[] source,
int sourceOff,
int sourceCount,
int targetOffset,
int targetCount,int fromIndex) -->([CII[CIII)I
attributes_count: 用于存放一些额外的信息,字段都可以在属性表中描述>=0个额外信息。如果属性表计数器为0,则attribute_info不占用空间。
本例子中:attributes_count
为 0x0000.
注:
① 字段集合中不会列出从超类或者父类中继承(或接口继承)出来的字段,单有可能列出原本java中不存在的字段(内部类)②字段无法重载,两个字段的数据类型、修饰符不管是否相同,都必须使用不一样的名称,但是对于字节码来说,如果两个字段的描述符不一样,那字段重名就是合法的。
五、方法表集合
同样先来看方法表结构:
这个结构和字段表相似,access_flags
包括:
通过上表我们发现:并没有具体说明方法中的代码如何在字节码文件中存储的,其实是存放在方法属性表集合中一个名为“Code”的属性中。
注:在 方法表集合的前面,还有一个u2类型表示一共有几个方法;
在上一个的例子中值为:0x0002,代表有两个方法(inc()、)
然后才到方法表集合:
来看 access_flags
: 0x0001,很好理解Acc_PUBLIC
为真
name_index
: 0x0007,指向第7个常量 <init>
descriptor_index
: 0x0008 ,指向第8个常量()V
attributes_count
: 0x0001,表示此方法的属性表集合有一项属性
attributes_info
: 0x0009,指向第9个常量Code,说明此属性是方法的字节码描述
注: 如果父类方法在子类中没有被重写(Override),方法表集合中就不会出现来自父类的方法信息。同样,有可能出现有编译器自动添加的方法,最经典的便是类构造器“”和实例构造器“”方法