java虚拟机原理6,《Java虚拟机原理图解》6、 class文件中的方法表集合--method方法在class文件中是怎样组织的...

0. 前言

了解JVM虚拟机原理是每一个Java程序员修炼的必经之路。但是由于JVM虚拟机中有很多的东西讲述的比较宽泛,在当前接触到的关于JVM虚拟机原理的教程或者博客中,绝大部分都是充斥的文字性的描述,很难给人以形象化的认知,看完之后感觉还是稀里糊涂的。

感于以上的种种,我打算把我在学习JVM虚拟机的过程中学到的东西,结合自己的理解,总结成《Java虚拟机原理图解》 这个系列,以图解的形式,将抽象的JVM虚拟机的知识具体化,希望能够对想了解Java虚拟机原理的的Java程序员 提供点帮助。

1.概述

方法表集合是指由若干个方法表(method_info)组成的集合。对于在类中定义的若干个,经过JVM编译成class文件后,会将相应的method方法信息组织到一个叫做方法表集合的结构中,字段表集合是一个类数组结构,如下图所示:

2. method方法的描述-方法表集合在class文件中的位置

method方法的描述-方法表集合紧跟在字段表集合的后面(想了解字段表集合的读者可以点击我查看),如下图所示:

3. 一个类中的method方法应该包含哪些信息?----method_info结构体的定义

对于一个方法的表示,我们根据我们可以概括的信息如下所示:

实际上JVM还会对method方法的描述添加其他信息,我们将在后面详细讨论。如上图中的method_info结构体的定义,该结构体的定义跟描述field字段 的field_info结构体的结构几乎完全一致,如下图所示。

方法表的结构体由:访问标志(access_flags)、名称索引(name_index)、描述索引(descriptor_index)、属性表(attribute_info)集合组成。

名称索引(name_index):

描述索引(descriptor_index):

属性表(attribute_info)集合:

接下来,我们将一一击破它们,看看它们到底是怎么表示的。

4. 访问标志(access_flags)---记录着method方法的访问信息

5. 名称索引和描述符索引----一个方法的签名

关于不同的数据类型的描述符是怎样的,我已经在《Java虚拟机原理图解》1.4 class文件中的字段表集合--field字段在class文件中是怎样组织的  第五部分字段的数据类型表示和字段名称表示 进行过详细的阐释,感兴趣的读者可以前去查看。

举例:对于如下定义的的greeting()方法,我们来看一下对应的method_info结构体中的名称索引和描述符索引信息是怎样组织的。public static synchronized final void greeting(){

}             如下图所示,method_info结构体的名称索引中存储了一个索引值x,指向了常量池中的第x项,第x项表示的是字符串"greeting",即表示该方法名称是"greeting";描述符索引中的y 值指向了常量池的第y项,该项表示字符串"()V",即表示该方法没有参数,返回值是void类型。

6.属性表集合--记录方法的机器指令和抛出异常等信息

属性表集合记录了某个方法的一些属性信息,这些信息包括:

属性表(attribute_info)结构体的一般结构如下所示:

6.1 Code类型的属性表--method方法中的机器指令的信息

异常处理跳转信息---exception_table:

Java源码行号和机器指令的对应关系---LineNumberTable属性表:

局部变量表描述信息----LocalVariableTable属性表:

举例:

如下定义Simple类,使用javac -g:none Simple.java 编译出Simple.class 文件,并使用javap -v Simple > Simple.txt 查看反编译的信息,然后看Simple.class文件中的方法表集合是怎样组织的:package com.louis.jvm;

public class Simple{

public static synchronized final void greeting(){

int a = 10;

}

}

1. Simple.class文件组织信息如下所示:

如上所示,方法表集合使用了蓝色线段圈了起来。

请注意:方法表集合的头两个字节,即方法表计数器(method_count)的值是0x0002,它表示该类中有2个方法。细心的读者会注意到,我们的Simple.java中就定义了一个greeting()方法,为什么class文件中会显示有两个方法呢??

在Simple.classz中出现了两个方法表,分别代表构造方法()和greeting()方法,现在让我们分别来讨论这两个方法:

2.  Simple.class 中的() 方法:

解释:

11.显式异常表集合(exception_table_count): 占有2 个字节,值为0x0000,表示方法中没有需要处理的异常信息;

12. Code属性表的属性表集合(attribute_count): 占有2个字节,值为0x0000,表示它没有其他的属性表集合,因为我们使用了-g:none 禁止编译器生成Code属性表的LineNumberTable 和LocalVariableTable;

B.  Simple.class 中的greeting() 方法:

解释:

1. 方法访问标志(access_flags): 占有2个字节,值为0x0039 ,即二进制的00000000 00111001,即标志位的第11、12、13、16位为1,根据上面讲的方法标志位的表示,可以得到该greeting()方法的修饰符有:ACC_SYNCHRONIZED、ACC_FINAL、ACC_STATIC、ACC_PUBLIC;

2.名称索引(name_index): 占有2个字节,值为0x0007,指向常量池的第7 项,该项表示字符串“greeting”,即该方法的名称是“greeting”;

3. 描述符索引(descriptor_index): 占有2个字节,值为0x0005,指向常量池的第5 项,该项表示字符串“()V”,即表示该方法不带参数,并且无返回值;

4. 属性计数器(attribute_count): 占有2个字节,值为0x0001,表示该方法表中含有一个属性表,后面会紧跟着一个属性表;

5.属性表的名称索引(attribute_name_index):占有2个字节,值为0x0006,指向常量池中的第6项,该项表示字符串“Code”,表示这个属性表是Code类型的属性表;

6. 属性长度(attribute_length):占有4个字节,值为0x0000 0010,即十进制的16,表明后续的16个字节可以表示这个Code属性表的属性信息;

7. 操作数栈的最大深度(max_stack):占有2个字节,值为0x0001,表示栈帧中操作数栈的最大深度是1;

8. 局部变量表的最大容量(max_variable):占有2个字节,值为0x0001,JVM在调用该方法时,根据这个值设置栈帧中的局部变量表的大小;

9. 机器指令数目(code_length):占有4个字节,值为0x0000 0004,表示后续的4个字节0x10、 0x0A、 0x3B、0xB1的是表示机器指令;

10.机器指令集(code[code_length]):这里共有4个字节,值为0x10、 0x0A、 0x3B、0xB1 ;

11.显式异常表集合(exception_table_count): 占有2 个字节,值为0x0000,表示方法中没有需要处理的异常信息;12. Code属性表的属性表集合(attribute_count): 占有2个字节,值为0x0000,表示它没有其他的属性表集合,因为我们使用了-g:none 禁止编译器生成Code属性表的LineNumberTable 和LocalVariableTable;

6.2 Exceptions类型的属性表----method方法声明的要抛出的异常信息

7.  IDE代码提示功能实现的基本原理

现在对于企业级的开发,开发者们越来越依赖IDE如Intellij IDEA、Eclipse、MyEclipse、NetBeans等,利用他们提供的高级功能,可以极大地提高编码的速度和效率。

每个IDE都提供了代码提示功能,它们实现的基本原理其实就是IDE针对它们项目下的包中所有的class文件进行建模,解析出它们的方法信息,当我们一定的条件时,IDE会自动地将合适条件的方法列表展示给开发者,供开发者使用。

8.  写在后面

以上就是Class文件的方法表集合的全部内容。

读者可能觉得本文关于方法表的Code属性表讨论的不够深入,在讨论Code属性表的时候,我简单介绍了它的两个属性表LineNumberTable 和LocalVariableTable这两个在有什么实际作用,但是没有详细第介绍它们,并且在列举的例子中,刻意地使用了  -g:none 选项 ,以使生成的class文件没有这两项信息,这么做是因为Code 属性太过复杂,而本文主要是想让读者了解的是 方法表集合,所以就生成了最精简的Code属性表,以减少读者的负担。

接下来的一篇文章,我打算专门来讨论Code属性表,揭开Code属性表的所有秘密,敬请关注~~

本文还引出了一个需要讨论的话题:就是Code属性表中的机器指令,机器指令的运行要依赖于JVM体系结构的设计机制,理解机器指令的运行机制,这将是根非常非常难啃的骨头.......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值