JVM(一 · 下)带你解读字节码
JVM(一 ·上) 一篇文章让你了解字节码是什么
JVM(一 · 中)带你解读字节码
JVM(一 · 下)带你解读字节码
6.父类(super_class)
当前类的父类
表示指定在常量池的位置
0004
0x0004=4
#4
07 0015
这个又指向#21
#21
01 0010 6a61 7661 2f6c 616e 672f 4f62 6a65 6374
acsii码表查询结果:java/lang/Object
这里可以看出,这个类继承了Object类,所有类都继承这个类,所以我们没写,它也继承了。
7.接口(interfaces)
当前类实现的接口
接口数量(interfaces_count)
0000
我这里没有实现任何接口,当然接口数量为0啦。
接口列表(interfaces)
如果有接口的话,后面会接interfaces_count* 4位16进制数,每个u2对应这常量池中的位置
8.字段(fields)
字段是指当前类的属性,不是方法内部的属性
字段个数(fields_count)
0001
说明这个类有一个属性
然后我们读取后面的16位16进制数
字段列表(fields)
字段类型
表示字符 | 含义 |
---|---|
B | byte字节类型 |
J | long长整型 |
C | char字符类型 |
S | short短整型 |
D | double双精度浮点 |
Z | boolean布尔型 |
F | float单精度浮点 |
V | void类型 |
I | int整型 |
L | 对象引用类型 |
字段
0002 0005 0006 0000
第一个u2:字段的标记类型,标记类型,需要翻看前面的标记类型
第二个u2:字段的名称,对应这常量池中的位置
第三个u2:字段的类型,对应这常量池中的位置,需要翻看字段的类型
第四个u2:字段的属性,对应这常量池中的位置
0002说明这个字段为private类型
0005指向常量池#5
#5
0100 0161
acsii码表查询结果:a
0006指向常量池#6
#6
0100 0149
acsii码表查询结果:I
I对应着int整型
0000指向#0,表示不作索引,也就是为null
如果在定义该属性时有赋值(int类型0是默认值),这个u2会指向一个不为null的常量
拼起来就是private int a;
9.方法(methods)
当前类的方法
方法个数(methods_count)
0002
有两个方法,然而我们只定义了一个方法,那另外一个方法是哪里来的呢?
我们可以直接用idea打开编译好的.class文件,就可以看到,另外一个方法是构造方法
方法(methods)
我们先往后读6*4位16进制数
方法的描述
0001 0007 0008 0001
第一个u2:方法的标记类型,标记类型,需要翻看前面的标记类型
第二个u2:方法的名称,对应这常量池中的位置
第三个u2:方法的类型,对应这常量池中的位置,需要翻看字段的类型
第四个u2:方法的属性个数
翻译过来就是 public ()V
有一个属性
方法的属性
我们需要往后读3*4位16进制数,这几位数说明了该方法的属性情况
0009 0000 0038
第一个u2:属性的名称,对应这常量池中的位置
第二个u4:属性描述的长度,表示后面的u2个数,都是对属性的描述
第一个u2指向#9
#9
01 0004 436f 6465
acsii码表查询结果:Code
这个Code是JVM虚拟机已经预定义好的属性,相当于方法内部的代码,详情去百度搜一下“JVM虚拟机规范预定义的属性”,这里我就不展开讲述了
第二个u2:0x38=56
那我们再往后读56*2位16进制数
0002 0001 0000 000a 2ab7 0001 2a03
b500 02b1 0000 0002 000a 0000 000a
0002 0000 0003 0004 0004 000b 0000
000c 0001 0000 000a 000c 000d 0000
Code的属性结构
第一个u2:属性的最大堆数
第二个u2:属性的最大本地内存
第三个u4:指令描述的长度,表示后面的u2个数
第四个n*u2:指令,需要参照JVM 虚拟机字节码指令表
第五个u2:异常处理
第六个u2:属性的属性个数
·······后面就是属性的描述了
属性的解读跟前面的属性解读一样,但是需要注意的是,这些属性一般都是JVM虚拟机已经预定义好的属性,所以要按照相应的属性结构进行解读。
这里我就不解读了,
10.类属性
这个就是当前类的属性了
最后的几位16进制数就是对类属性的描述了
属性的个数
00 01
表示有一个属性
属性的描述
00 1000 0000 0200 11
第一个u2:属性常量的索引,对应这常量池中的位置
第二个u4:属性描述的长度,表示后面的u2个数
n*u2:对应这常量池中的位置
五、总结
.class文件的结构
魔数
cafe babe
版本号
0000 0034
常量池
0016
0a00 0400 12
09 0003 0013
0700 14
07 0015
0100 0161
0100 0149
0100 063c 696e 6974 3e
01 0003 2829 56
01 0004 436f 6465
0100 0f4c 696e 654e 756d 6265 7254 6162 6c65
0100 124c 6f63 616c 5661 7269 6162 6c65 5461 626c 65
01 0004 7468 6973
0100 134c 7465 7374 2f42 7974 6543 6f64 6554 6573 743b
0100 0367 6574
0100 0328 2949
0100 0a53 6f75 7263 6546 696c 65
01 0011 4279 7465 436f 6465 5465 7374 2e6a 6176 61
0c 0007 0008
0c00 0500 06
01 0011 7465 7374 2f42 7974 6543 6f64 6554 6573 74
01 0010 6a61 7661 2f6c616e 672f 4f62 6a65 6374
当前类的访问标记
0021
当前类
0003
父类
0004
实现接口数
0000
字段
0001
0002 0005 0006 0000
方法
方法个数
0002
方法描述
0001 0007 0008 0001
方法属性描述
0009 0000 0038
0002 0001 0000 000a 2ab7 0001 2a03
b500 02b1 0000 0002 000a 0000 000a
0002 0000 0003 0004 0004 000b 0000
000c 0001 0000 000a 000c 000d 0000
0001 000e 000f 0001
0009 0000 002f
0001 0001 0000 0005 2ab4 0002 ac00
0000 0200 0a00 0000 0600 0100 0000
0600 0b00 0000 0c00 0100 0000 0500
0c00 0d00 00
类属性
00 0100 1000 0000 0200 11
启示
通过这次字节码的学习,我了解到了字节码的组成,java源代码是怎么编译成.class文件的。
但是这个可真难啊,什么都是规定死了的,只要对着结构表就可以解读了。
——————————————————————————————
如果本文章内容有问题,请直接评论或者私信我。
未经允许,不得转载!
我看到一个用JSON表示的.class文件的结构,我觉得特别不错,篇幅太长了,但是篇幅太长了,我只好再创一片文章来展示了。