?

疯狂java

?
您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java Class文件结构实例分析(下)


 

      本篇我们继续分析Class文件结构的方法及属性部分内容,上节内容回顾请查看:
 
Java Class文件结构实例分析(上)
 
Class文件格式信息
 
 
继续上节实例代码
package chapter6;
public class TestClass {
    private int m;
    public int inc() {
        return m + 1;
    }
}
使用JDK1.8编译成class文件,然后通过WinHex打开
 
方法
 
上节我们分析到字段部分,字段的完整地址范围:000000E1~000000EA。
 
跟在字段后面的是方法,下面继续分析。
 
方法计数器(methods_count)
类型:u2 
字节地址:000000EB~000000EC 
值:0x0002
 
说明当前类有2个方法。
 
第1个方法
访问标志(access_flags)
类型:u2 
字节地址:000000ED~000000EE 
值:0x0001
 
查表得到对应的访问标志为ACC_PUBLIC。
 
名称索引(name_index)
类型:u2 
字节地址:000000EF~000000F0 
值:0x0007
 
 
对应常量池中的第7项常量,值为<init>,即实例初始化方法。
 
描述符(descriptor_index)
类型:u2 
字节地址:000000F1~000000F2 
值:0x0008
 
对应常量池中的第8项常量,值为()V,说明该方法无参数,返回类型为void。
 
由前3项可知,第1个方法为类的实例初始化方法。
 
属性计数器(attributes_count)
类型:u2 
字节地址:000000F3~000000F4 
值:0x0001
 
说明该字段有1个属性。
 
属性的通用格式如下:
 
第1个属性
名称索引(attribute_name_index)
类型:u2 
字节地址:000000F5~000000F6 
值:0x0009
 
对应常量池中的第9项常量,值为Code。
 
属性值的长度(attribute_length)
类型:u4 
字节地址:000000F7~000000FA 
值:0x0000002F
 
将0x0000002F转换为十进制,计算得到47。
 
操作数栈的最大深度(max_stack)
类型:u2 
字节地址:000000FB~000000FC 
值:0x0001
 
即最大深度为1。操作数栈的最大深度,由编译期决定。
 
局部变量的个数(max_locals)
类型:u2 
字节地址:000000FD~000000FE 
值:0x0001
 
即局部变量的个数为1。局部变量的个数,由编译期决定。
 
max_locals的单位是Slot,Slot是虚拟机为局部变量分配内存所使用的最小单位。对于长度不超过32位的数据类型,每个局部变量占用1个Slot。而double和long的数据类型长度为64位,需要占用两个Slot。
 
code[]数组的字节数(code_length)
类型:u4 
字节地址:000000FF~00000102 
值:0x00000005
 
字节码指令(code)
类型:u1 
长度/字节数:5 
字节地址:00000103~00000107
 
其中,第0、1、4字节为字节码指令,第2、3字节为参数索引。
 
常量池
 
实例初始化方法字节码指令信息
 
其中,初始化方法是没有参数的,但args_size为1。这其实是因为对于非static方法,编译器默认会将指向当前对象的this作为方法的第一个参数,以便在调用方法的时候使用。
 
异常表长度(exception_table_length)
类型:u2 
字节地址:00000108~00000109 
值:0x0000
 
说明没有异常表信息。
 
异常表(exception_table)
 
属性计数器(attributes_count)
类型:u2 
字节地址:0000010A~0000010B 
值:0x0002
 
说明该字段有2个属性。
 
第1个方法Code属性的第1个属性
名称索引(attribute_name_index)
 
类型:u2 
字节地址:0000010C~0000010D 
值:0x000C
 
对应常量池中的第12项常量,值为LineNumberTable,即字节码与源码的行号信息。
 
LineNumberTable属性值的长度(attribute_length)
 
类型:u4 
字节地址:0000010E~00000111 
值:0x00000006
 
LineNumberTable行号表的长度(line_number_table_length)
 
类型:u2 
字节地址:00000112~00000113 
值:0x0001
 
字节码与源码行号(字节地址:00000114~00000117)
 
第1个方法Code属性的第2个属性
名称索引(attribute_name_index)
 
类型:u2 
字节地址:00000118~00000119 
值:0x000D
 
对应常量池中的第13项常量,值为LocalVariableTable,即方法的本地变量表信息。
 
LocalVariableTable属性值的长度(attribute_length)
 
类型:u4 
字节地址:0000011A~0000011D 
值:0x0000000C
 
将0x0000000C转换为十进制,计算得到12。
 
LocalVariableTable局部变量表的长度(local_variable_table_length)
 
类型:u2 
字节地址:0000011E~0000011F 
值:0x0001
 
LocalVariableTable第1个局部变量(字节地址:00000120~00000129)
 
start_pc和length两者结合起来就是这个局部变量在字节码之中的作用域范围。
 
也就是说,这个局部变量为this,类型为chapter6/TestClass,存放在局部变量表的第0个Slot,作用域为code[0]~code[4]。
 
 
第1个方法对应的字节内容
 
第2个方法
访问标志(access_flags)
类型:u2 
字节地址:0000012A~0000012B 
值:0x0001
 
查表得到对应的访问标志为ACC_PUBLIC。
 
名称索引(name_index)
类型:u2 
字节地址:0000012C~0000012D 
值:0x0010
 
对应常量池中的第16项常量,值为inc,正是我们定义的实例方法名。
 
描述符(descriptor_index)
类型:u2 
字节地址:0000012E~0000012F 
值:0x0011
 
对应常量池中的第17项常量,值为()I,说明该方法无参数,返回类型为int。
 
以上3项,说明该方法定义为public int inc()。
 
属性计数器(attributes_count)
类型:u2 
字节地址:00000130~00000131 
值:0x0001
 
说明该字段有1个属性。
 
第1个属性
名称索引(attribute_name_index)
类型:u2 
字节地址:00000132~00000133 
值:0x0009
 
对应常量池中的第9项常量,值为Code。
 
Code属性值的长度(attribute_length)
类型:u4 
字节地址:00000134~00000137 
值:0x00000031
 
将0x00000031转换为十进制,计算得到49。
 
Code操作数栈的最大深度(max_stack)
类型:u2 
字节地址:00000138~00000139 
值:0x0002
 
即最大深度为2。
 
Code局部变量的个数(max_locals)
类型:u2 
字节地址:0000013A~0000013B 
值:0x0001
 
即局部变量的个数为1。
 
code[]数组的字节数(code_length)
类型:u4 
字节地址:0000013C~0000013F 
值:0x00000007
 
Code字节码指令(code)
类型:u1 
长度/字节数:7 
字节地址:00000140~00000146
 
其中,第0、1、4、5、6字节为字节码指令,第2、3字节为参数索引。
 
常量池
 
实例初始化方法字节码指令信息
 
Code异常表长度(exception_table_length)
类型:u2 
字节地址:00000147~00000148 
值:0x0000
 
说明没有异常表信息。
 
Code异常表(exception_table)
 
Code属性计数器(attributes_count)
类型:u2 
字节地址:00000149~0000014A 
值:0x0002
 
说明该字段有2个属性。
 
第2个方法Code属性的第1个属性
名称索引(attribute_name_index)
 
类型:u2 
字节地址:0000014B~0000014C 
值:0x000C
 
对应常量池中的第12项常量,值为LineNumberTable。
 
值为LineNumberTable属性值的长度(attribute_length)
 
类型:u4 
字节地址:0000014D~00000150 
值:0x00000006
 
值为LineNumberTable行号表的长度(line_number_table_length)
 
类型:u2 
字节地址:00000151~00000152 
值:0x0001
 
字节码与源码行号(字节地址:00000153~00000156)
 
第2个方法Code属性的第2个属性
名称索引(attribute_name_index)
 
类型:u2 
字节地址:00000157~00000158 
值:0x000D
 
对应常量池中的第13项常量,值为LocalVariableTable。
 
LocalVariableTable属性值的长度(attribute_length)
 
类型:u4 
字节地址:00000159~0000015C 
值:0x0000000C
 
将0x0000000C转换为十进制,计算得到12。
 
LocalVariableTable局部变量表的长度(local_variable_table_length)
 
类型:u2 
字节地址:0000015D~0000015E 
值:0x0001
 
LocalVariableTable第1个局部变量(字节地址:0000015F~00000168)
 
start_pc和length两者结合起来就是这个局部变量在字节码之中的作用域范围。
 
也就是说,这个局部变量为this,类型为chapter6/TestClass,存放在局部变量表的第0个Slot,作用域为code[0]~code[6]。
 
第2个方法对应的字节内容
 
类的属性计数器(attributes_count)
类型:u2 
字节地址:00000169~0000016A 
值:0x0001
 
说明该类有1个属性。
 
第1个属性
名称索引(attribute_name_index)
类型:u2 
字节地址:0000016B~0000016C 
值:0x0014
 
对应常量池中的第12项常量,值为SourceFile,即class文件的Java源文件名称。
 
属性值的长度(attribute_length)
类型:u4 
字节地址:0000016D~00000170 
值:0x00000002
 
类的源文件名称索引(sourcefile_index)
类型:u2 
字节地址:00000171~00000172 
值:0x0015
 
对应常量池中的第21项常量,值为TestClass.java。
 
?