前言
大家好,不知不觉已经到 9 月份了,本篇文章是 Java 类机制的最后一篇,我们来一起探讨一下关于 Java 的字节码和方法调用。本篇文章参考了《深入理解 JVM 虚拟机》一书。
在开始之前我们先回顾一下在之前讲过的内容,在 Java 类机制(3)---- 类文件结构 中我们解析了已经编译好的 .class
文件的内容结构。其中包括
magic
、minor_version
、major_version
…methods_count
、methods
等结构。通过上篇文章我们已经知道一个 methods
结构中包含了某个方法的具体信息,其中就包含了这个方法代码的字节码表示,我们再来看看 methods
的结构:
类型 | 名称 | 数量 | 含义 |
---|---|---|---|
u2 | access_flag | 1 | 方法的访问标识 |
u2 | name_index | 1 | 方法名常量在常量池中的下标 |
u2 | descriptor_index | 1 | 方法描述常量在常量池中的下标 |
u2 | attributes_count | 1 | 额外属性信息数量 |
attribute_info | attributes | attributes_count | 额外属性信息 |
其中,attritube_info
描述了方法的额外信息,其表结构如下:
类型 | 名称 | 数量 | 含义 |
---|---|---|---|
u2 | attribute_name_index | 1 | 属性名在常量池中的常量下标 |
u4 | attributes_length | 1 | 属性数据的长度 |
u1 | info(这里是统称,实际的数据由具体的表类型决定) | attributes_length | 属性数据 |
注意这里的 attritube_info
描述的是一类属性表的一般结构,并不是具体的某一个属性表,attritube_info
表的 info
字段描述的是这个属性表的数据,具体是何种数据需要根据 attribute_name_index
指向的常量池中的常量来决定,比如说当 attribute_name_index
指向的常量值为 ConstantValue
时,代表这个额外属性表的具体类型为 ConstantValue
类型,这个类型的表结构如下:
类型 | 名称 | 数量 | 含义 |
---|---|---|---|
u2 | attribute_name_index | 1 | 属性名在常量池中的常量下标 |
u4 | attributes_length | 1 | 属性数据的长度 |
u1 | constantValue_index | attributes_length | 指向常量池中下标为 constantValue_index 的常量 |
对应上面的 attribute_info
表:其 info
字段在 ConstantValue
表中的具体体现即为 constantValue_index
字段。而如果 attritube_info
表中的 attribute_name_index
字段指向的常量值为 Code
,则代表当前的属性表的具体类型为 Code
类型,一个方法(即 methods
结构)中是一定会有一个名为 Code
的额外属性表的。这个表的具体类型如下:
类型 | 名称 | 数量 | 含义 |
---|---|---|---|
u2 | attribute_name_index | 1 | 属性表名在常量池中的常量下标 |
u4 | attributes_length | 1 | 属性数据的长度 |
u2 | max_stack | 1 | 方法执行时操作数栈深度的最大值 |
u2 | max_locals | 1 | 方法执行时局部变量表所需要的存储空间,这里的单位 Slot,一个 Slot 可以储存长度不超过32位的局部变量值 |
u4 | code_length | 1 | 代码编译成字节码之后的代码长度 |
u1 | code | code_length | 代码内容,每一个字节数据对应一个字节码 |
u2 | exception_table_length | 1 | 方法的异常表长度 |
exception_info | exception_table | exception_table_length | 方法抛出的异常信息 |
u2 | attribute_count | 1 | 额外属性表数目 |
attribute_info | attributes | attribute_count | 额外属性表信息 |
这个时候 attribute_in