Java Class文件结构实例分析(下)_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Java Class文件结构实例分析(下)

Java Class文件结构实例分析(下)

 2018/9/8 1:00:23  zhanjia  程序员俱乐部  我要评论(0)
  • 摘要:发表文章之后,发现很多图片显示不了,请阅读我的公众号文章,以获得本文最佳体验:JavaClass文件结构实例分析(下)本篇我们继续分析Class文件结构的方法及属性部分内容,上节内容回顾请查看:JavaClass文件结构实例分析(上)Class文件格式信息继续上节实例代码packagechapter6;publicclassTestClass{privateintm;publicintinc(){returnm+1;}}使用JDK1.8编译成class文件
  • 标签:文件 Java 实例 分析 实例分析 class

发表文章之后,发现很多图片显示不了,请阅读我的公众号文章,以获得本文最佳体验:

Java Class文件结构实例分析(下)

?

本篇我们继续分析Class文件结构的方法及属性部分内容,上节内容回顾请查看:

Java Class文件结构实例分析(上)

Class文件格式信息

继续上节实例代码

class="java language-java hljs" style="margin: 0px 2px; padding: 0.5em; font-size: 14px; color: #a9b7c6; line-height: 18px; border-radius: 0px; background: #282b2e; font-family: Consolas, Inconsolata, Courier, monospace; display: block; letter-spacing: 0px;">package?chapter6;
public?class?TestClass?{
????private?int?m;
????function" style="margin: 0px; padding: 0px; font-size: inherit; color: #f82375; line-height: inherit;">public?int?inc()?{
????????return?m?+?1;
????}
}

使用JDK1.8编译成class文件,然后通过WinHex打开

方法

上节我们分析到字段部分,字段的完整地址范围:000000E1~000000EA。

跟在字段后面的是方法,下面继续分析。

方法计数器(methods_count)

类型:u2?
字节地址:000000EB~000000EC?
值:0x0002

说明当前类有2个方法。

第1个方法

访问标志(access_flags)

类型:u2?
字节地址:000000ED~000000EE?
值:0x0001

查表得到对应的访问标志为ACC_PUBLIC。

名称索引(name_index)

类型:u2?
字节地址:000000EF~000000F0?
值:0x0007

对应常量池中的第7项常量,值为<init>,即实例初始化方法。

描述符(descriptor_index)

类型:u2?
字节地址:000000F1~000000F2?
值:0x0008

对应常量池中的第8项常量,值为()V,说明该方法无参数,返回类型为void。

由前3项可知,第1个方法为类的实例初始化方法。

属性计数器(attributes_count)

类型:u2?
字节地址:000000F3~000000F4?
值:0x0001

说明该字段有1个属性。

属性的通用格式如下:

第1个属性

名称索引(attribute_name_index)

类型:u2?
字节地址:000000F5~000000F6?
值:0x0009

对应常量池中的第9项常量,值为Code。

属性值的长度(attribute_length)

类型:u4?
字节地址:000000F7~000000FA?
值:0x0000002F

将0x0000002F转换为十进制,计算得到47。

操作数栈的最大深度(max_stack)

类型:u2?
字节地址:000000FB~000000FC?
值:0x0001

即最大深度为1。操作数栈的最大深度,由编译期决定。

局部变量的个数(max_locals)

类型:u2?
字节地址:000000FD~000000FE?
值:0x0001

即局部变量的个数为1。局部变量的个数,由编译期决定。

max_locals的单位是Slot,Slot是虚拟机为局部变量分配内存所使用的最小单位。对于长度不超过32位的数据类型,每个局部变量占用1个Slot。而double和long的数据类型长度为64位,需要占用两个Slot。

code[]数组的字节数(code_length)

类型:u4?
字节地址:000000FF~00000102?
值:0x00000005

字节码指令(code)

类型:u1?
长度/字节数:5?
字节地址:00000103~00000107

其中,第0、1、4字节为字节码指令,第2、3字节为参数索引。

常量池

实例初始化方法字节码指令信息

其中,初始化方法是没有参数的,但args_size为1。这其实是因为对于非static方法,编译器默认会将指向当前对象的this作为方法的第一个参数,以便在调用方法的时候使用。

异常表长度(exception_table_length)

类型:u2?
字节地址:00000108~00000109?
值:0x0000

说明没有异常表信息。

异常表(exception_table)

属性计数器(attributes_count)

类型:u2?
字节地址:0000010A~0000010B?
值:0x0002

说明该字段有2个属性。

第1个方法Code属性的第1个属性

名称索引(attribute_name_index)

类型:u2?
字节地址:0000010C~0000010D?
值:0x000C

对应常量池中的第12项常量,值为LineNumberTable,即字节码与源码的行号信息。

LineNumberTable属性值的长度(attribute_length)

类型:u4?
字节地址:0000010E~00000111?
值:0x00000006

LineNumberTable行号表的长度(line_number_table_length)

类型:u2?
字节地址:00000112~00000113?
值:0x0001

字节码与源码行号(字节地址:00000114~00000117)

第1个方法Code属性的第2个属性

名称索引(attribute_name_index)

类型:u2?
字节地址:00000118~00000119?
值:0x000D

对应常量池中的第13项常量,值为LocalVariableTable,即方法的本地变量表信息。

LocalVariableTable属性值的长度(attribute_length)

类型:u4?
字节地址:0000011A~0000011D?
值:0x0000000C

将0x0000000C转换为十进制,计算得到12。

LocalVariableTable局部变量表的长度(local_variable_table_length)

类型:u2?
字节地址:0000011E~0000011F?
值:0x0001

LocalVariableTable第1个局部变量(字节地址:00000120~00000129)

start_pc和length两者结合起来就是这个局部变量在字节码之中的作用域范围。

也就是说,这个局部变量为this,类型为chapter6/TestClass,存放在局部变量表的第0个Slot,作用域为code[0]~code[4]。

第1个方法对应的字节内容

第2个方法

访问标志(access_flags)

类型:u2?
字节地址:0000012A~0000012B?
值:0x0001

查表得到对应的访问标志为ACC_PUBLIC。

名称索引(name_index)

类型:u2?
字节地址:0000012C~0000012D?
值:0x0010

对应常量池中的第16项常量,值为inc,正是我们定义的实例方法名。

描述符(descriptor_index)

类型:u2?
字节地址:0000012E~0000012F?
值:0x0011

对应常量池中的第17项常量,值为()I,说明该方法无参数,返回类型为int。

以上3项,说明该方法定义为public int inc()。

属性计数器(attributes_count)

类型:u2?
字节地址:00000130~00000131?
值:0x0001

说明该字段有1个属性。

第1个属性

名称索引(attribute_name_index)

类型:u2?
字节地址:00000132~00000133?
值:0x0009

对应常量池中的第9项常量,值为Code。

Code属性值的长度(attribute_length)

类型:u4?
字节地址:00000134~00000137?
值:0x00000031

将0x00000031转换为十进制,计算得到49。

Code操作数栈的最大深度(max_stack)

类型:u2?
字节地址:00000138~00000139?
值:0x0002

即最大深度为2。

Code局部变量的个数(max_locals)

类型:u2?
字节地址:0000013A~0000013B?
值:0x0001

即局部变量的个数为1。

code[]数组的字节数(code_length)

类型:u4?
字节地址:0000013C~0000013F?
值:0x00000007

Code字节码指令(code)

类型:u1?
长度/字节数:7?
字节地址:00000140~00000146

其中,第0、1、4、5、6字节为字节码指令,第2、3字节为参数索引。

常量池

实例初始化方法字节码指令信息

Code异常表长度(exception_table_length)

类型:u2?
字节地址:00000147~00000148?
值:0x0000

说明没有异常表信息。

Code异常表(exception_table)

Code属性计数器(attributes_count)

类型:u2?
字节地址:00000149~0000014A?
值:0x0002

说明该字段有2个属性。

第2个方法Code属性的第1个属性

名称索引(attribute_name_index)

类型:u2?
字节地址:0000014B~0000014C?
值:0x000C

对应常量池中的第12项常量,值为LineNumberTable。

值为LineNumberTable属性值的长度(attribute_length)

类型:u4?
字节地址:0000014D~00000150?
值:0x00000006

值为LineNumberTable行号表的长度(line_number_table_length)

类型:u2?
字节地址:00000151~00000152?
值:0x0001

字节码与源码行号(字节地址:00000153~00000156)

第2个方法Code属性的第2个属性

名称索引(attribute_name_index)

类型:u2?
字节地址:00000157~00000158?
值:0x000D

对应常量池中的第13项常量,值为LocalVariableTable。

LocalVariableTable属性值的长度(attribute_length)

类型:u4?
字节地址:00000159~0000015C?
值:0x0000000C

将0x0000000C转换为十进制,计算得到12。

LocalVariableTable局部变量表的长度(local_variable_table_length)

类型:u2?
字节地址:0000015D~0000015E?
值:0x0001

LocalVariableTable第1个局部变量(字节地址:0000015F~00000168)

start_pc和length两者结合起来就是这个局部变量在字节码之中的作用域范围。

也就是说,这个局部变量为this,类型为chapter6/TestClass,存放在局部变量表的第0个Slot,作用域为code[0]~code[6]。

第2个方法对应的字节内容

类的属性计数器(attributes_count)

类型:u2?
字节地址:00000169~0000016A?
值:0x0001

说明该类有1个属性。

第1个属性

名称索引(attribute_name_index)

类型:u2?
字节地址:0000016B~0000016C?
值:0x0014

对应常量池中的第12项常量,值为SourceFile,即class文件的Java源文件名称。

属性值的长度(attribute_length)

类型:u4?
字节地址:0000016D~00000170?
值:0x00000002

类的源文件名称索引(sourcefile_index)

类型:u2?
字节地址:00000171~00000172?
值:0x0015

对应常量池中的第21项常量,值为TestClass.java。

字节码内容


?

参考

《Java虚拟机规范》(Java SE 8版)

《深入理解Java虚拟机 JVM高级特性与最佳实践》

?

转载请注明来源:http://zhanjia.iteye.com/blog/2430257

?

个人公众号

二进制之路

?

发表评论
用户名: 匿名