【JVM】带你解读字节码(上)

JVM(一 ·上) 一篇文章让你了解字节码是什么
JVM(一 · 中)带你解读字节码
JVM(一 · 下)带你解读字节码

三、java字节码的组成

1.基本数据类型

数据类型含义
u1 无符号单字节整数
u2 无符号2字节整数
u4 无符号4字节整数
u8 无符号8字节整数

1Byte=8bit,在十六进制中,需要用两位数来表示1Byte。
一个十六进制数需要4bit来表示。

2.java字节码的格式

类型数量名称含义
u4 1 magic 魔数
u2 1 minor_version 副版本号
u2 1 major_version 主版本号
u2 1 constant_pool_count 常量数
cp_info constant_pool_count-1 constant_pool 常量池列表
u2 1 access_flags 访问标记
u2 1 this_class 当前类
u2 1 super_class 父类
u2 1 interfaces_count 实现的接口数
u2 interfaces_count interfaces 接口列表
u2 1 fields_count 字段个数
field_info fields_count fields 字段列表
u2 1 methods_count 方法个数
method_info methods_count methods 方法列表
u2 1 attribute_count 属性个数
attribute_info attributes_vount attributes 属性列表

3.格式解读

为了节省空间,java对字节码的格式有严格要求,所以我们能够照着这个格式表来对字节码进行解读。
非基础数据类型的类型其实也是有基础数据类型来组成的,也是严格按照一定的格式来存放数据的。
可以看到常量池、接口、字段、方法、属性都是采用数量+数据的格式进行存储的。

四、解读字节码

以上面我们创建的ByteCodeTest.class文件为例。

1.魔数(magic)

cafe babe

这个数使用来表示当前文件类型的,这个是有java之父James Gosling设定的。在代码内部也有魔数,一般被叫做魔法值,一般是指在方法内部的常量值。

2.版本号(version)

0000 0034

副版本为0,主版本为52
对应java1.8(8),这个需要根据住版本跟副版本去查询。

3.常量池(constant_pool)

常量池中存储的是不会发生变化的数据。

常量池基本类型

在这里插入图片描述

常量个数(constant_pool_count)

0016

0x16=22
这里指定了常量的个数,常量的个数为22,#0~#22,实际个数为21
为什么要减一我也不是很懂,有的说是因为#0不作为常量,有的说#0表示什么都不引用。

常量池列表(pool_count)

在观察常量时,需要先根据开头的一个字节判断它是什么类型,然后才能知道它的长度

#1

0a00 0400 12

0x0a=10,对应地找到了CONSTANT_Methodref_info
这个类型会引用两个u2(2bit),也就是8位16进制
所以这里是10个十六进制数表示一个常量

0x0004=4
0x0012=12
所以这个常量引用了#4、#12

全部常量
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 2f6c 616e 672f 4f62 6a65 6374 

每一行都代表一个常量
类型为CONSTANT_UTF-8_info还需要另查ACSII码表

4.访问标记(access_flags)

访问标记

标记类型

标志名称值(16进制)位(bit)描述
PUBLIC 0x0001 0000000000000001 对应public类型的类
PRIVATE 0x0002 0000000000000010 字段为private
PROTECTED 0x0004 0000000000000100 字段为protected
STATIC 0x0008 0000000000001000 字段为static
FINAL 0x0010 0000000000010000 对应类的final声明
SUPER 0x0020 0000000000100000 标识JVM的invokespecial新语义
VOLATILE 0x0040 0000000000100000 字段是否为volatile
TRANSIENT 0x0080 0000000001000000 字段是否为transient
INTERFACE 0x0200 0000001000000000 接口标志
ABSTRACT 0x0400 0000010000000000 抽象类标志
SYNTHETIC 0x1000 0001000000000000 标识这个类并非用户代码产生
ANNOTATION 0x2000 0010000000000000 标识这是一个注解
ENUM 0x4000 0100000000000000 标识这是一个枚举

访问标记是根据每个bit上的0/1来标记的,从表中可以看出它是以16bit来表示的。

0021

访问标记并不是直接对着表找,就可以找到是属于那个类型的。
0x0021=0000000000100001,可以对照表格找到,它在PUBLIC和SUPER上,所以这个类具有public和super标志

5.当前类(this_class)

当前类
表示指定在常量池的位置

0003

0x0003=3
说明当前类对应#3,也就是
#3

0700 14

这个又指向#20
#20

01 0011 7465 7374 2f42 7974 6543 6f64 6554 6573 74
acsii码表查询结果:test/ByteCodeTest

 

posted @ 2020-05-27 13:11  程序员徐小白  阅读(324)  评论(0)    收藏  举报