欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JVM(一 · 下)带你解读字节码

程序员文章站 2022-04-18 14:48:10
...

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文件的结构,我觉得特别不错,篇幅太长了,但是篇幅太长了,我只好再创一片文章来展示了。