java class文件格式
本文讲解如何解析java class文件
以jdk8作为演示
1. class文件结构
u2、u4等代表占用字节数
1 |
|
本文中使用以下代码作为演示
1 |
|
idea hexview插件显示对应的字节码文件(十六进制)
2. 魔数
前四个字节ca fe ba be代表魔数(Magic Number),标识这个文件是一个java类文件。
3. 版本号
第5和第6个字节代表次版本号,第7和第8个字节代表主版本号。
次版本号:00 00
主版本号:00 34,十进制为52
java版本从45开始,52代表java8
4. 常量池
4.1 constant_pool_count
9、10两个字节代表常量池中的项数(constant_pool_count),索引为0项的无效。
即索引大于0且小于constant_pool_count被认为是有效的
00 24:常量池项数, 十进制为36,即有35项常量
4.2 constant_pool
常量池标签
常量池标签结构
从第10个字节往后有35个常量信息。
常量信息的第一个字节对应常量池标签中的类型,后续占用的字节以常量池标签结构为准。
0a为第一个字节,十进制为10,10在常量标签中代表方法引用,方法引用的标签结构占用5个字节,从0a开始计算。
第一个常量:0a 00 06 00 16
#1 = Methodref #6.#22
Methodref的class_index引用了第6项常量信息
Methodref的name_and_type_index引用了第22项常量信息
通过javap反编译后
5.类访问标识
最后一个常量的后两个字节为访问标识。
当前类字节码中为00 21,值为多个相加。
6. 类名,父类名,接口名集合
6.1 类名
访问标识后两个字节为当前类全限定名。
00 05:引用了常量池中的第5项,即为demo/jvm/ClassFile
6.2 父类名
类名后两个字节为父类的全限定名
00 06:引用了常量池中的第6项,即为java/lang/Object
6.3 接口名集合
父类名称后两位为接口数量(interfaces_count)
00 00 当前类未实现任何接口,数量为0。
如果有,后续的2个字节代表一个接口信息,也是引用了常量池中常量项,
没有则不会有字节记录接口信息。
7. 字段
字段结构
1 |
|
字段访问标识
字段描述符
接口信息后两个字节为字段数量(fields_count)
00 01:有一个字段。
第一个字段字节码:00 00 00 07 00 08 00 00
00 00:访问标识,表示当前字段无任何访问标识(同类访问标识相同)
00 07:字段名称,引用了常量池中第7项,即a
00 08:字段描述符,引用了常量池中的第8项,即J,J在字段描述符中表示long类型
00 00:其他属性,无其他属性
8.方法
方法结构
1 |
|
方法访问标识
方法描述符
1 |
|
属性结构
以下只列出Code属性结构,其它可从属性文档中查看
1 |
|
字段结束后的2个字节为方法数量(methods_count)
00 02:有两个方法
第一个方法字节码:00 01 00 09 00 0a 00 01 00 0b 00 00 00 2f 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00 00 02 00 0c 00 00 00 06 00 01 00 00 00 03, 00 0d 00 00 00 0c 00 01 00 00 00 05 00 0e 00 0f 00 00
方法信息:
00 01:访问标识,public的
00 09:方法名称,引用常量池中第9项,即<init>构造方法
00 0a:方法描述符,十进制为10,引用常量池中第10项,即()V,无参无返回值
00 01:其他属性1个
属性信息:
00 0b:属性名称,十进制为11,引用了常量池中第7项,即Code
00 00 00 2f: 属性长度,十进制为47,后续的47个字节是当前属性内容
00 01:操作数栈的最大深度
00 01:局部变量表中最大槽数
00 00 00 05 :字节码长度
2a b7 00 01 b1:字节码指令
00 00:异常表中的条目数
00 02:属性Code的细节属性数量
后续的其它属性解析是一样的,对应属性结构即可
9.属性信息
0001 0014 0000 0002 0015
00 01:属性数量
00 14:属性名称,十进制为20,引用常量池中第20项,即SourceFile
00 00 00 02:属性长度,后续2个字节是当前属性的内容
00 15:源文件名称,十进制为21,引用常量池中第21项,即ClassFile.java