字节码文件基本组成部分解析 。字节码文件中的十六进制数据中
每两个文字符号为一个字节。
1. 魔数
在字节码文件中,魔数占据了4个字节
在我们以上的字节码数据中,从0开始数4个字节就是我们的魔数,
java语言中,魔数固定为 【 CAFEBABE 】
2. 版本号
魔数后的4个字节为版本号,主次版本号分别占据2个字节 ,
十六进制数据 : 00000033 -> jdk版本为 51
3. 常量池
版本号后面 2个字节为常量池大小的定义: 0019 -> 25
可以看到常量池的大小为24 (25-1)
索引0 为保留常量 null,不位于常量表中
3.1 常量池表分析
根据下面的常量池表进行分析:
我们得到常量池分析的结束位置:
4. AccessFlag访问标志
常量池结束 accessflag占据2个字节 : 0021
这个表里面无法直接查询到0021这个值,原因是0021=0020+0001,也就是表示当前class的access_flag是ACC_PUBLIC|ACC_SUPER
参考下表:
5. ClassName 类名
访问标识后面2个字节: 0003 说明类名在常量池表中的索引为 3
6. SuperClassName 父类名
类名后占据2个字节: 0004 ,在常量池的索引为4
7. 接口 interface名
父类后占据2个字节: 0000 因为我们的类,没有实现接口所以为0
8. fields
占据2个字节: 0001 数量为1
8.1 字段表结构
每个成员变量对应一个field_info结构:
field_info {
u2 access_flags; 0002
u2 name_index; 0005
u2 descriptor_index; 0006
u2 attributes_count; 0000
attribute_info attributes[attributes_count];
}
access_flags为0002,即是ACC_PRIVATE
name_index指向常量池的第五个常量,为“test”
descriptor_index指向常量池的第6个常量为“I”
三个字段结合起来,说明这个变量是"private int test"。
接下来的是attribute字段,用来描述该变量的属性,因为这个变量没有附加属性,所以attributes_count为 0,attribute_info为空。
9. methods
占据2个字节: 0004
9.1 方法表结构
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
9.2 0009 code 结构表
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{
u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
attribute_length表示attribute所包含的字节数,这里为0000001d,即是39个字节,不包含 attribute_name_index和attribute_length字段。
max_stack表示这个方法运行的任何时刻所能达到的操作数栈的最大深度,这里是0001
max_locals表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量,这里是0001.
接下来的code_length表示该方法的所包含的字节码的字节数以及具体的指令码。
这里的字节码长度为00000005,即是后面的5个字节 2a b7 00 01 b1为对应的字节码指令的指令码。
参照下表可以将上面的指令码翻译成对应的助记符:
9.3 属性表结构
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}