与字段表集合相对应,如果父类方法在子类中没有被覆盖,方法表中就不会出现父类的方法的信息,但同样,有可能会出现会出现由编译器自动添加的方法,最典型的就是类构造器“<cinit>”方法和实例狗构造器"<init>"方法。
在Java语言中,要重载一个方法,除了要方法与原方法的简单名称一样之外,还必须要求拥有一个与原方法不同的特征签名,特诊签名就是一个方法中各个参数在常量池中字段符号引用的集合,但是返回值不包含在特征签名中,因此Java语言中想要覆盖一个方法的话,如果是返回值不同是无法覆盖的。
方法表的结构:
方法访问标志:
九、属性表集合(attributes)在Class文件,字段表和方法表中都可以携带自己的属性表集合,用于描述某些场景下专有的信息。属性表集合没有那么严格的限定,不再要求各个属性表具有严格的顺序,并且只要不予已有的属性表的名字重复,任何人实现的编译器都可以想属性表中写入自己定义的属性信息,但Java虚拟机在运行时会忽略掉它不认识的属性。Java虚拟机规范中预定义了9中虚拟机应当被识别的属性(jdk1.5后又增加了一些新的特性),如下表:
对于每个属性,它的名称都需要从常量池中引用的一个CONSTANT_Utf8_info类型的常量来表示,每个属性值的结构完全可以自定义,只需说明属性值所需暂用的位数长度即可,一个符合规范的属性表至少应具备attribute_name_info”、“attribute_length”和至少一项信息属性。
1)Code属性前面已经提到过,Java程序的方法体中的代码经过编译器编译后,生成的字节码指令会存储在Code属性中,但并非所有的方法表都有属性表,比如抽象类和接口中可能不存在属性表。属性表的结构如下如所示:
attribute_name_index是一项指向CONSTANT_Utf8_info型常量的索引,常量固定值为 "Code",它代表了该属性的名称。attribute_length表示属性值的长度,由于属性名称索引与属性长度一共是6个字节,所以属性值长度为整个属性表长度减去 6个字节。
max_stack代表操作数栈的最大深度,max_locals代表了局部变量表所需要的空间,它的单位为slot。
code_length和code是用来存储Java源程序编译后生成的字节码指令。code用于存储字节码指令的一些列字节流,它是u1类型的单字节,因此取值范围为0x00到0xFF,那么一共可以存储256条指令,目前,Java虚拟机规范中已经定义了200条指令。code_length为u4类型,理论上可以达到2^32-1,但是虚拟机中明确的规定了一个方法不允许超过65525条字节码指令,如果超过了这个数值,编译器将拒绝编译。
字节码指令之后是这个方法显示处理的异常表集合(exception_table),对于属性表来说这个属性不是必须存在的,它的格式如下表所示:
它包含四个字段,这些字段的含义是如果字节从 start_pc 到 end_pc 行之间(不含end_pc)出现了 catch_pc类型或者它的子类类型的异常(catch_type为指向一个CONSTANT_Class_info型常量的索引),则转到第handler_pc行继续处理,当catch_pc为0时,代表任何的异常都要转到handler_pc行进行处理。异常表实际上的Java代码的一部分,编译器使用异常表而不是简单地使用跳转的命令来实现Java的异常即finally处理机制,也因此,finally里面的代码内容会在try或catch中的return语句调用之前调用。
2)Exception属性这里的Exception属性的作用是列举出方法中可能会出现的受检查异常,也就是方法描述是throws关键字后面列举的异常,它的结构很简单,只有attribute_name_index、attribute_length、number_of_exceptions、exception_index_table四项。
3)LineNumberTable属性它用于描述Java源码行号与字节码行号之间的对应关系。
4)LocalVariableTable属性它用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的对应关系。
5)SourceFile属性它用于记录生成这个Class文件的源码文件名称。
6)ConstantValue属性