三、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
——————————————————————————————
如果本文章内容有问题,请直接评论或者私信我。
未经允许,不得转载!