先做网站先备案,一级造价工程师教材,建e网室内设计效果图新中式,怎么自己做游戏软件内容导航摘要环境实践源代码对应class文件class文件查看class整体结构class解读征途(人工)1、魔数2、主版本号3、副版本号4、常量池计数5、常量信息数组5.1、常量15.1.1、常量类型5.2、常量286、访问标志7、类索引8、父类索引9、直接接口计数器10、接口信息表11、字段计数器12、…内容导航摘要环境实践源代码对应class文件class文件查看class整体结构class解读征途(人工)1、魔数2、主版本号3、副版本号4、常量池计数5、常量信息数组5.1、常量15.1.1、常量类型5.2、常量286、访问标志7、类索引8、父类索引9、直接接口计数器10、接口信息表11、字段计数器12、字段信息表13、方法计数器14、方法信息表14.1、方法114.1.1、访问标志(access_flags)14.1.2、方法名索引值(name_index)14.1.3、描述索引(descriptor_index)14.1.4、其他属性的数量(attributes_count)14.1.5、其他属性信息表14.1.5.1、其它属性信息114.1.5.1.1、属性名索引值14.1.5.1.2、属性长度14.1.5.1.3、 属性表14.2、方法214.2.1、访问标志(access_flags)14.2.2、方法名索引值(name_index)14.2.3、描述索引(descriptor_index)14.2.4、其他属性的数量(attributes_count)14.2.5、其他属性信息表14.2.5.1、其它属性信息114.2.5.1.1、属性名索引值14.2.5.1.2、属性长度14.2.5.1.3、 操作数堆栈的最大深度14.2.5.1.4、局部变量的数量14.2.5.1.5、指令数组长度14.2.5.1.6、指令信息表14.2.5.1.6.1、指令信息114.2.5.1.7、异常表长度14.2.5.1.7、异常表14.2.5.1.8、Code的属性数量14.2.5.1.9、Code的属性信息14.2.5.1.9.1、属性114.2.5.1.9.1.1、属性名索引14.2.5.1.9.1.2、属性长度14.2.5.1.9.1.3、行数表长度14.2.5.1.9.1.3、行数表14.2.5.1.9.1.3.1、行数据114.2.5.1.9.1.3.2、行数据215、属性计数器16、属性信息表16.1、属性信息116.1.1、属性名索引16.1.2、属性长度16.1.3、源文件索引摘要您好 本篇旨在借助Hello World小程序讲解class文件结构希望给您在您理解class结构的路上推波助澜。如有不足请不吝赐教。环境JavaJDK8JVM DocJava SE 8class查看器winhex实践源代码喜闻乐见Hello World源码如下public class HelloWorld { public static void main(String[] args) { System.out.println(Hello World); } }对应class文件javac编译HelloWorld.java生成HelloWorld.class。其过程就不废话class文件查看1、用上面列出的工具winhex打开HelloWorld.class如下说明图片是以1字节为基本单位的十六进制表示的class内容class实际还是二进制存储的只不过为了容易查看将二进制转为十六进制而已。2、使用如下javap命令查看HelloClass.class结构:显示内容如下此为虚拟机解读出来的结果。我们要做的就是模拟虚拟机解读过程。class整体结构参照官方虚拟机规范文档可知class文件伪结构如下ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; }不一一说明直接看下图。再有不明白就看官方虚拟机规范文档.图片说明方格中有文字的都是所占字节长度不确定无文字的都是占1字节(魔数也在其列方格中的只是作为固定值展示而已)。class解读征途(人工)记住一点class文件是一串严格有序、无分隔符、无对齐符的二进制流。1、魔数长度4字节值0xCAFEBABE对应位置说明固定值为了表示此文件为一个class文件。2、主版本号长度2字节值0x0000对应位置对应javap展示结果3、副版本号长度2字节值0x0034对应十进制52对应位置说明与上面次版本号组合标志class文件的版本。如主版本号为M次版本号为m则class文件版本为 M.m。对应javap展示结果4、常量池计数长度2字节值0x001D对应位置说明十六进制换算成十进制为29对应数组索引为0 ~ 28但索引0位置是虚拟机预留的不可使用。故索引范围实际为1 ~ 28表示容量池中仅有28个常量元素。5、常量信息数组常量是一个包含多个无符号数和项的复合数据结构。常量的通用伪结构模板如下cp_info { u1 tag; u1 info[]; }因结构中未指定info[]长度所以不能直接确定一个常量的具体长度。唯一可确定的是常量都是以一个字节的tag常量类型开始所以只能先确定常量类型再确定具体的伪结构。5.1、常量15.1.1、常量类型长度1字节值0x0A对应位置说明十六进制转为十进制对应值为10参照常量类型表可知此常量类型为CONSTANT_Methodref,对应的实际伪结构如下CONSTANT_Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; }所以常量1对应数据位置三个红色小框分别对应伪结构的三项tag、class_index、name_and_type_index。项目十六进制值十进制值解析值tag0x0A10CONSTANT_Methodrefclass_index0x00066name_and_type_index0x000F15对应javap结果5.2、常量28因篇幅问题省略其它常量的分析过程直接最后一个常量。说明由于常量类型0x01查常量类型表可知该常量类型为CONSTANT_Utf8用来表示常量字符串值。而其对应伪结构如下CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; }关于tag上面已经说过length占2字节对应下面字节数组包含的元素数量。u1 bytes[length]表示字节数组也即下面是连续length个各占一字节的无符号数最终应该是个字符串。项目十六进制值十进制值解析值tag0x011CONSTANT_Utf8length0x000615bytes[length]0x28、0x4C、0x6A、0x61、0x76、0x61、0x2F、0x6C、0x61、0x6E、0x67、0x2F、0x53、0x74、0x72、0x69、0x6E、0x67、0x3B、0x29、0x56(Ljava/lang/String;)V对应位置说明关于字节数组bytes[]转字符串可以查询ASCII对照表可以自己试一试这里不累赘。到此常量池中的内容分析结束让我们查看一下常量池全内容6、访问标志长度2字节值0x0021对应位置说明0x0021转为二进制为对照上图可知分别对应ACC_SUPER、ACC_PUBLIC对应javap展示结果7、类索引长度2字节值0x0005对应位置说明此值为常量池索引值此索引对应的常量的类型必须为CONSTANT_Class对应javap展示结果8、父类索引长度2字节值0x0006对应位置对应javap展示结果说明此值为常量池索引值非0索引对应的常量的类型必须为CONSTANT_Class索引0则表示父类为Object。源码中HelloWorld并没有显式继承父类这里确出现父类java.lang.Object。正好应证了java.lang.Object是所有类(除去Object)的父类。9、直接接口计数器长度2字节值0x0000对应位置说明十进制数为0表示没有显式实现接口。官方对此项的说明为The value of the interfaces_count item gives the number of direct superinterfaces of this class or interface type.我理解为该类或接口类型显式实现或继承的接口数量。10、接口信息表因为接口计数器指定值为0索引接口表为空11、字段计数器长度2字节值0x0000对应位置说明十进制为0表示没有字段12、字段信息表因字段计数器指定值为0此部分为空13、方法计数器长度2字节值0x0002对应位置说明十进制值为2有2个方法。14、方法信息表方法的伪结构如下method_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; }14.1、方法114.1.1、访问标志(access_flags)长度2字节值0x0001对应位置说明指定十进制值为1查方法访问标志表可知对应ACC_PUBLIC对应javap展示结果14.1.2、方法名索引值(name_index)长度2值0x0007对应位置说明对应常量池索引值7所存的常量该常量类型必须为CONSTANT_Utf8对应javap展示结果14.1.3、描述索引(descriptor_index)长度2字节值0x0008对应位置说明对应常量池索引值8所存的常量该常量类型必须为CONSTANT_Utf8对应javap展示结果14.1.4、其他属性的数量(attributes_count)长度2字节值0x0001对应位置说明此值表示该方法还有一个属性说明14.1.5、其他属性信息表其它属性的伪结构如下attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info [attribute_length]; }14.1.5.1、其它属性信息114.1.5.1.1、属性名索引值长度2字节值0x0009对应位置说明对应常量池索引9对应的常量该常量类型必须为CONSTANT_Utf8对应javap展示结果14.1.5.1.2、属性长度长度4字节值0x0000001D对应位置:14.1.5.1.3、 属性表根据上面属性长度所指示的值为29表示接下来29个连续的各占1字节的均为属性信息。长度29字节值0x00、0x01、0x00、0x01、0x00、0x00、0x00、0x05、0x2A、0xB7、0x00、0x01、0xB1、0x00、0x00、0x00、0x01、0x00、0x0A、0x00、0x00、0x00、0x06、0x00、0x01、0x00、0x00、0x00、0x01对应位置说明根据属性名code查询官网文档可知该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]; }则此部分内容应该对应伪结构中从u2 max_stack开始的所有项。具体我会在对第二个方法解读时候详解。14.2、方法214.2.1、访问标志(access_flags)长度2字节值0x0009对应位置说明指定十进制值为9查方法访问标志表可知对应ACC_PUBLIC、ACC_STATIC对应javap展示结果14.2.2、方法名索引值(name_index)长度2值0x0007对应位置说明对应常量池索引值11所存的常量该常量类型必须为CONSTANT_Utf8对应javap展示结果14.2.3、描述索引(descriptor_index)长度2字节值0x0008对应位置说明对应常量池索引值12所存的常量该常量类型必须为CONSTANT_Utf8对应javap展示结果14.2.4、其他属性的数量(attributes_count)长度2字节值0x0001对应位置说明此值表示该方法还有一个属性说明14.2.5、其他属性信息表其它属性的通用伪结构如下attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info [attribute_length]; }14.2.5.1、其它属性信息114.2.5.1.1、属性名索引值长度2字节值0x0009对应位置说明对应常量池索引9对应的常量该常量类型必须为CONSTANT_Utf8对应javap展示结果则该属性实际伪结构如下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]; }与方法1一致这里就直接按实际伪结构一一解读。14.2.5.1.2、属性长度长度4字节值0x00000025对应位置:14.2.5.1.3、 操作数堆栈的最大深度长度2字节值0x0002对应位置对应javap展示结果14.2.5.1.4、局部变量的数量长度2字节值0x0001对应位置说明包括用于在调用该方法时将参数传递给该方法的局部变量。对于long或double类型值的最大局部变量索引是 max_locals - 2。任何其他类型的值的最大局部变量索引为max_locals - 1。对应javap展示结果14.2.5.1.5、指令数组长度长度4字节值0x00000009对应位置14.2.5.1.6、指令信息表一个字节代表一条指令可参照官方指令说明14.2.5.1.6.1、指令信息1长度1字节值0xB2对应位置查询官方指令对照表可知表示指令 getstatic对应javap展示结果余下指令查询结果如下字节码指令00nop02iconst_m112ldc03iconst_0B6invokevirtual00nop04iconst_1B1return14.2.5.1.7、异常表长度长度2字节值0x0000对应位置14.2.5.1.7、异常表由上面属性可知为空此项无14.2.5.1.8、Code的属性数量长度2字节值0x0001对应位置14.2.5.1.9、Code的属性信息通用为伪结构如下attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info[attribute_length]; }14.2.5.1.9.1、属性114.2.5.1.9.1.1、属性名索引长度2字节值0x000A对应位置对应javap展示结果查询官网可知实际对应伪结构为LineNumberTable_attribute { u2 attribute_name_index; u4 attribute_length; u2 line_number_table_length; { u2 start_pc; u2 line_number; } line_number_table[line_number_table_length]; }14.2.5.1.9.1.2、属性长度长度4字节值0x0000000A对应位置14.2.5.1.9.1.3、行数表长度长度2字节值0x0002对应位置14.2.5.1.9.1.3、行数表之前伪结构中已经给出为{ u2 start_pc; u2 line_number; }14.2.5.1.9.1.3.1、行数据1项目开始位置行号对应值0x00000x0003十进制03对应位置对应javap展示结果14.2.5.1.9.1.3.2、行数据2项目开始位置行号对应值0x00080x0004十进制84对应位置对应java展示结果位置15、属性计数器长度2字节值0x0001对应位置16、属性信息表伪结构如下attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info[attribute_length]; }16.1、属性信息116.1.1、属性名索引长度2字节值0x000D对应位置对应javap展示结果则该属性实际的伪结构为SourceFile_attribute { u2 attribute_name_index; u4 attribute_length; u2 sourcefile_index; }16.1.2、属性长度长度4字节值0x00000002对应位置:16.1.3、源文件索引长度2字节值0x000E对应位置对应javap展示结果