结构体 volatile_「编译引擎」学习阅读Class文件结构(16进制版)-中

本文详细解读了JVM Class文件中关于类的描述,包括访问标识、继承结构、字段表的各个组成部分,如字段计数器、字段访问标志、字段名和描述符等,通过实例分析了如何从字节码中获取类的字段和方法信息。
摘要由CSDN通过智能技术生成

在《「编译引擎」学习阅读Class文件结构(16进制版)-上 》中,笔者讲解了如何以16进制的方式,解读Demo2.java对应字节码的常量池。

我们继续解读Demo2.class字节码的属性表、方法表等重要的片段。

1.对类的描述:访问标识

JVM规范:The value of the access_flags item is a mask of flags used to denote access permissions to and properties of this class or interface.

在字节码文件中,紧接着常量池之后,2个字节表示了当前类或者接口访问标识。

它的结构如下:

301a5a3427eb7a2d2babc4eff090eb4b.png

我们看一下第35个常量之后紧接着的2个字节:

f48e4a3e5b3661d338b4d4f5c76ebf25.png

这个值=00 21,对照JVM规范可知,0x0021 = 0x0001 | 0x0020,表示当前类是public类型的,如下图所示的含义:

6d75b0a651ac09142d7ed0066fa5822c.png

这两个字节,表示的就是演练代码中红框处内容:

72325a774fdd8d2569b386412c70c161.png

2.继承结构:类索引/父类索引/接口列表

JVM规范:

The value of the this_class item must be a valid index into the constant_pool table.

For a class, the value of the super_class item either must be zero or must be a valid index into the constant_pool table.

The value of the interfaces_count item gives the number of direct superinterfaces of this class or interface type.

2个字节表示当前类索引

2个字节表示父类索引

2个字节表示接口计数器、N个字节(N=接口计数器的值)表示接口索引列表(每个接口索引占2个字节)。

dfecb191531bcd89e81bc65444b531ee.png

我们看一下下图红框处的6个字节:

3a50b3708b6bfd6fbc67454a63b85361.png

00 06表示常量池中第6个常量(CONSTANT_Class类型),进而指向了第28个常量(CONSTANT_Utf8类型),表示的就是Demo2类。

00 07表示常量池中第6个常量(CONSTANT_Class类型),进而指向了第28个常量(CONSTANT_Utf8类型),表示的就是Demo2的父类——Object类。

00 00表示接口计数器为0,表示Demo2类没有实现任何接口。

041eeaf73fac37b9bfb8ff9110ade827.png

这些字节码表达了红框处代码的信息:

3661c9a55add66f3b87ba1c84a1f2085.png

3.类的成员们:字段表

3.1.字段计数器

JVM规范:The value of the fields_count item gives the number of field_info structures in the fields table

475db1ea815c6276dac8c1fd366a5681.png

红框处的2个字节00 01,表示Demo2类中有1个字段

e18f7d277ba1e815d3b1ada7f088ae93.png

3.2.JVM如何表示一个字段

JVM规范:Each field is described by a field_info structure.

No two fields in one class file may have the same name and descriptor

JVM为了表示类中的一个字段(例如:一个实例变量),用如下数据结构表示:

访问标志:2个字节,就是这个字段的访问权限,例如:private、public等。

字段名索引:2个字节,就是这个字段的在常量池中的索引。

字段描述符:2个字节,就是这个字段的类型。

14bfbba8d39cd2d0778951867f3781db.png

3.3.字段访问标志

JVM规范:The value of the access_flags item is a mask of flags used to denote access permission to and properties of this field.

JVM认为字段访问标志包括:public、private、protected,也包括static、final、volatile、transient,还包括enum修饰符

具体如下表:

36e4d1e07489d39d4f687ecb0aad0408.png

在Demo2类的字节码中,显示值为00 02,说明Demo2有1个字段,字段为private。

815394ae1c8fa2e11d67360289528f30.png

对应Demo2的代码如下图红框:

c078d41db1c8ffac085ed98e90e16877.png

3.3.字段名索引

JVM规范:The value of the name_index item must be a valid index into the constant_pool table.

如同其它"索引"类型的信息片段,JVM也是用在常量池的索引表示字段名。

97fb9acd6e84a5a53223470113c63bf5.png

在Demo2的字节码中,字段名索引值=00 08

352b016b79b0e7f47c6c13d397b08b03.png

00 08表示了常量池第8个常量,第8个常量为CONSTANT_Utf8类型,就是字面量"field1"

0070e24a80d9189045c5af740bc6cef5.png

Demo2源码中,也说明,Demo2类中实例变量名就是field1

14ee74534f0f6ca153dffdf99daca58e.png

3.4.字段描述符

JVM规范:The value of the descriptor_index item must be a valid index into the constant_pool table.

2个字节的字段描述符,就是表示字段的数据类型,例如:int、byte、char、double或者对象引用等。

631cea179f2339fb11ce80b94a322efa.png

Demo2的字节码中,00 09就是字段field1的描述符:

58444ea2f5344b54511bc9900ab2db06.png

00 09表示field1的类型可以去查常量池的第9个常量,第9个常量是CONSTANT_Utf8类型,值为I,I表示的就是int

61349c4cf01637493168325a4913cd90.png

看到Demo2的源码中,field1的数据类型就是int

a085c8ebd9520865921a5f332c24bd82.png

4.类的行为集合:方法表

4.1.方法计数器

JVM规范:The value of the methods_count item gives the number of method_info structures in the methods table.

JVM用2个字节,表示类中具有多少个方法。

3b3816a3b7ab34a078f959b9d0b99746.png

Demo2的字节码中,00 02说明有2个方法。

03290768dd5cc9443c1ce3df9a5832b6.png

可是Demo2的源码中,不是只有一个方法hello吗?

那是因为Demo2还有一个构造函数,JVM将构造函数命名为方法。

JVM还会在某些场景下生成方法,笔者将在后续文章中阐述。

5fe81a130f46873ba80328273f56dc74.png

4.2.JVM如何表示一个方法

JVM规范:Each method, including each instance initialization method and the class or interface initialization method, is described by a method_info structure.

要用一种数据结构表达方法,最基本的有3个要素:

  • 方法的访问权限
  • 方法名
  • 方法返回值类型

进一步,方法体、方法内的局部变量等等怎么表达呢?

JVM采用了属性表来表示它们,这一部分,也是笔者认为"广义的编译器"非常聪明、非常巧妙的信息表示方法。

下图摘自JVM规范,方法内部的信息采用属性表表示,属性表中每一个属性又可以嵌套一个子属性表。

这样就形成了一个多级的属性树。

72b0e64018801cc04dbb6ceb32711bd2.png

这里表述的很抽象,我们接下来以Demo2中的hello方法为例,具象化地理解JVM表达方法的method_info以及下属的属性树。

下图红框,就是hello方法,在字节码中的信息片段。

1316a9e264641552cef0e80a6e4897dc.png

4.3.hello方法的访问标识符

JVM规范:The value of the access_flags item is a mask of flags used to denote access permission to and properties of this method.

方法访问标识符包括:public/private/protected,也包括static/final,还包括synchronized/native,以及abstract等等。

可以看到方法的访问标识符就是Java代码中,在方法名前面,对方法的各种访问限定,如下图:

10048c15f8be2b48b318cfd6fa0b4a66.png

Demo2的字节码中,访问标识符=00 01,根据上表,说明hello方法是public类型的:

984bcb7eb8d45f409df3db1957a9e201.png

对照Demo2的源代码,如下图:

f73221442d569578f3db1a28c279550d.png

4.4.hello方法名

JVM规范:The value of the name_index item must be a valid index into the constant_pool table.

这2个字节也是索引类型,指向了常量池中的常量。

084123c1dee76418d3241a371e7c2adf.png

Demo2的字节码中,00 11指向了第17个常量

407ca3901c57f27a40074c13c5692029.png

对照Demo2的源码,如下图:

1654952135ec9e3cd24334a26644813f.png

4.5.hello方法的描述符

JVM规范:The value of the descriptor_index item must be a valid index into the constant_pool table.

方法描述符,可以理解为方法的输入参数类型列表和返回值类型

629ac0293ce08110385b91c397229b9d.png

Demo2字节码的方法描述为00 08,指向了常量池中第11个常量,第11个常量的值="()V"

33962eeb57606bc17804194e215dacf5.png

()表示没有输入参数,V表示void类型的返回值:

f184a4216b729d2ab9662e13d7be1f67.png

对应Demo2的源代码:

46be5aaedc4b6f56031c08915ed7b8a1.png

4.6.hello方法的属性计数器

JVM规范:The value of the attributes_count item indicates the number of additional attributes of this method.

方法下,下挂了属性树,这2个字节就表示了属性个数。

17cd72896e38ad1de42f8c71c2c1ade0.png

Demo2的字节码中,00 01表示hello方法下挂了1个属性

adaf46f067fbbc55ed09d294b5ac95c7.png

在此,我们先剧透一下hello方法下挂的属性树结构:

f026eb85273e2070d7d151899e14d08b.png

从上图,我们可以得到2个信息:

  • JVM对于类中的方法,都会下挂一个Code属性,Code属性像一个容器,下面可以挂更多的子属性
  • LineNumberTable属性、LocalVariableTable属性,都是一种表结构类型的属性

5.总结:JVM如何描述一个类?

根据Demo2演练代码,JVM描述了如下信息:

5.1.类的信息

JVM字节码中构建了这样一颗与类有关的信息树

有一个叫Demo2的类,是public类型的,继承于Object类

98b94c76b5d27f0b219b12d98719f931.png

5.2.类中字段相关的信息

JVM构建了字节相关的信息树,遍历可知:

Demo2类中有一个字段field1,是private的,是int类型的

7bc991661635a4afb6e878fa4fbc9981.png

5.3.类中方法相关的信息

JVM构建了方法相关的信息树,遍历可知:

Demo2类中有一个方法叫做hello,是public的,没有输入也没有返回

39fe72f0f4f16723dcd8eb4709fa4c5a.png

6.下一步

笔者下篇会继续阅读本演练代码对应的Class文件剩余部分,包括

方法内部相关的信息

如果您能耐心地看到这句话,恭喜您,距离"看着16进制享受而诡魅的微笑"又近了一步,加油!

92b2095fb89355b8bf8be523249cbef4.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值