在 JVM 眼中 .class 文件是什么样的?值得收藏( 四 )


字段名索引:0x000B , 十进制值为11 , 指向常量池第11个常量 , 为y
描述符索引为:0x0009 , 指向常量池第9个常量 , 为I
属性表数为:0x0001 , 数量为1
属性表总占用长度为:u2 + u4 + 2字节 共10位 , 即 0x0167 ~ 0x016E
字段访问标志位含义如表:

在 JVM 眼中 .class 文件是什么样的?值得收藏

文章插图
 
当前为 private static final  , 即 0x0001 | 0x0008 | 0x0010  ,  为 0x001A 。
通过访问标志、字段索引、描述符信息 , 就可以拿到
-> private static final int y 这一信息 。
对于使用 final和static修饰的并且时基本数据类型的变量 , 会使用属性表ConstantVulue来进行赋值 。属性表 ConstantVulue 除了约定的基本数据外 , 还有类型为 u2 的ConstantValue_index 索引来表示指向常量池中的常量用来初始化数据 。值位于 0x016D ~ 0x016E , 为 0x000D , 指向的常量表索引13处的值为整型的20;
而实例中的变量m , 类变量x则在成员初始函数、类初始函数中进行赋值 , 下文做说明 。
07 方法表
字段表之后 , 紧挨着的是方法数量与方法表集合
在 JVM 眼中 .class 文件是什么样的?值得收藏

文章插图
 
范围为 0x016F ~ 0x0258 , 方法数值为 0x0005 共 5 个方法 。除了示例自定义的 increace()  , m() 和 hello() 外 , 还有实例构造方法<init>()v , 类构造器<clinit>()方法 。
方法表结构为:
伪代码
{
// 访问标志
u2 access_flags;
// 方法名索引 , 指向常量池类型为CONSTANT_Utf8_info的常量
u2 name_index;
// 方法返回值描述符索引 , 指向常量池类型为CONSTANT_Utf8_info的常量
u2 descriptor_index;
// 属性表数量
u2 attributes_count;
// 属性表内容
Info info;
}
方法也可以携带属性表来描述专有场景 。通过上述结构以及具体字节码 , 可以推算出方法所包含的内容 。其中 , 访问标志含义如表:
在 JVM 眼中 .class 文件是什么样的?值得收藏

文章插图
 
取构造实例方法方法<init>()做示例来看:
在 JVM 眼中 .class 文件是什么样的?值得收藏

文章插图
 
信息为:
access_flags: 0x0001  , 为public
name_index: 0x000E , 为14 , 对应常量池得到 <init>
descriptor_index: 0x000F , 为15 , 对应常量池得到 ()V
attributes_count: 0x0001 , 为1 , 属性表数量为1
可以根据信息反推得到函数信息 , 实例化函数被表达为 public <init>()V , 依次为访问标志位、函数名、返回值 。
一个函数方法 , 更重要的如何表述它所提供的功能 。本质上来说 , 函数体里所有的代码段都是在进行运算操作 , 因此 , 只要将函数体里的代码段转换为字节码指令即可 , 函数执行时根据执行即可 , 再次之上再几率一下关键信息 , 就能得出函数执行、栈深度、局部变量数、字节码占用文件大小 。
在attributes_count之后 , 从 0x0179 ~ 0x01A5 是属性表包含的内容 。根据之前所说的属性表约定的格式 0x0179 ~ 0x0180 位置值为 0x0010 , 十进制为16 , 查找啊常量池知属性表为Code类型 。Code类型属性表结构如下:
// 伪代码
{
// 属性表名称索引 , 指向常量表类型为CONSTANT_Utf8_info的常量
u2 attribute_name_index;
// 属性表长度
u4 attribute_length;
// 栈深
u2 max_stack;
// 局部变量数
u2 max_locals;
// 字节码指令长度
u4 code_length;
// 字节码指令
u1 code code_length;
// 异常表数量
u2 exception_table_length;
// 异常表
exception_info exception_table;
// 属性表数量
u2 attributes_count;
// 属性表
attribute_info attributes;
}
获取方法信息不仅能直接通过阅读字节码文件 , 通过javap -verbose className也可以拿到 , 一起贴了
在 JVM 眼中 .class 文件是什么样的?值得收藏

文章插图
 
红圈为字节码指令集 , 黄圈为每一条字节码指令 , 绿圈为Code属性表的基本信息 , 蓝圈为javap工具解析出的实例函数信息 。


推荐阅读