美文网首页
Java虚拟机-Class文件结构之方法表

Java虚拟机-Class文件结构之方法表

作者: 贪睡的企鹅 | 来源:发表于2019-07-31 16:53 被阅读0次

    1 解析示例

    示例源码

    public class ClassStructureMethod {
        public  void greeting() throws Exception {
           try {
               int a=1;
               int b=1;
               int c=a+b;
               System.out.println(c);
           }catch (Exception e){
               System.out.println("catch");
           }finally {
               System.out.println("finally");
           }
        }
    }
    

    示例常量池

    Constant pool:
       #1 = Methodref          #9.#30         // java/lang/Object."<init>":()V
       #2 = Fieldref           #31.#32        // java/lang/System.out:Ljava/io/PrintStream;
       #3 = Methodref          #33.#34        // java/io/PrintStream.println:(I)V
       #4 = String             #35            // finally
       #5 = Methodref          #33.#36        // java/io/PrintStream.println:(Ljava/lang/String;)V
       #6 = Class              #37            // java/lang/Exception
       #7 = String             #38            // catch
       #8 = Class              #39            // jvm/ClassStructureMethod
       #9 = Class              #40            // java/lang/Object
      #10 = Utf8               <init>
      #11 = Utf8               ()V
      #12 = Utf8               Code
      #13 = Utf8               LineNumberTable
      #14 = Utf8               LocalVariableTable
      #15 = Utf8               this
      #16 = Utf8               Ljvm/ClassStructureMethod;
      #17 = Utf8               greeting
      #18 = Utf8               a
      #19 = Utf8               I
      #20 = Utf8               b
      #21 = Utf8               c
      #22 = Utf8               e
      #23 = Utf8               Ljava/lang/Exception;
      #24 = Utf8               StackMapTable
      #25 = Class              #37            // java/lang/Exception
      #26 = Class              #41            // java/lang/Throwable
      #27 = Utf8               Exceptions
      #28 = Utf8               SourceFile
      #29 = Utf8               ClassStructureMethod.java
      #30 = NameAndType        #10:#11        // "<init>":()V
      #31 = Class              #42            // java/lang/System
      #32 = NameAndType        #43:#44        // out:Ljava/io/PrintStream;
      #33 = Class              #45            // java/io/PrintStream
      #34 = NameAndType        #46:#47        // println:(I)V
      #35 = Utf8               finally
      #36 = NameAndType        #46:#48        // println:(Ljava/lang/String;)V
      #37 = Utf8               java/lang/Exception
      #38 = Utf8               catch
      #39 = Utf8               jvm/ClassStructureMethod
      #40 = Utf8               java/lang/Object
      #41 = Utf8               java/lang/Throwable
      #42 = Utf8               java/lang/System
      #43 = Utf8               out
      #44 = Utf8               Ljava/io/PrintStream;
      #45 = Utf8               java/io/PrintStream
      #46 = Utf8               println
      #47 = Utf8               (I)V
      #48 = Utf8               (Ljava/lang/String;)V
    

    2 方法表前置结构

    image
    • 类访问标志2个字节(u2)来描述,对应16进制0x0021,对照Java虚拟机规范定义,匹配ACC_PUBLIC、ACC_SUPER,表示当前类的修饰符为public。

    • 类名用2位字节(u2)来描述,对应16进制0x0008,即十进制的8,8是常量池数组的一个下标,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Class_info类型的常量(下标#8),CONSTANT_Class_info类型常量其值转换为整数20,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Utf8_info类型的常量(下标#39),字符串值为"jvm/ClassStructureMethod"。

    • 父类名用2位字节(u2)来描述,对应16进制0x0009,即十进制的9,9是常量池数组的一个下标,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Class_info类型的常量(下标#9),CONSTANT_Class_info类型常量其值转换为整数21,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Utf8_info类型的常量(下标#40),字符串值为"java/lang/Object"。

    • 类接口数量用2位字节(u2)来描述,对应16进制0x0000,即十进制的0,表示当前类没有实现接口。因此Class文件中不存在接口名称描述。

    • 字段数量用2位字节(u2)来描述,对应16进制0x0000,即十进制的0,表示当前类没有字段。因此Class文件中不存在字段的描述。

    2 方法表结构

    方法表集合的结构

    方法表集合的结构被划分为方法表数量方法表集合。

    方法表数量(methods_count):表示类中定义的方法个数,其中除了自定义的方法外,每一个类中都会存在名称为"<init>"构造函数,如果类中定义静态变量或者静态块,则还会存在一个名称为"<clinit>"类初始化方法。

    方法表(method_info):表示类中定义某一个方法。其中涵盖了方法的所有信息。

    image

    3 方法表数量(methods_count)

    Java虚拟机规范中方法表数量用2个字节(u2)用来表示。

    示例中方法表数量

    示例中方法数量,对应16进制0x0002,即十进制的2,代表Class文件中有2个方法。

    image

    对比源代码中ClassStructureMethod类定义,存在一个构造方法<init>和自定义方法greeting(),共两个方法。

    public class ClassStructureMethod {
        public  void greeting() throws Exception {
           try {
               int a=1;
               int b=1;
               int c=a+b;
               System.out.println(c);
           }catch (Exception e){
               System.out.println("catch");
           }finally {
               System.out.println("finally");
           }
        }
    }
    

    Class文件中init方法的描述

    本章节主要用来解析greeting方法在Class文件中的结构,在此跳过<init>方法部分描述。

    Class文件中init方法的描述

    image

    4 方法表(methods_info)

    Java虚拟机规范定义方法表结构

    image
    • 方法访问标志(access_flags)
    • 方法名称索引(name_index)
    • 方法描述符索引(descriptor_index)
    • 方法属性表集合(attributes)
    4.1 方法访问标志(access_flags)

    Java虚拟机规范中方法访问标志用2个字节(u2)用来表示。

    Java虚拟机规范定义方法访问标志

    image

    示例中方法访问标志

    字段修饰符用2个字节(u2)来描述,对应16进制0x0001,对照JVM规范表中方法方法访问标志为ACC_PUBLIC,表示方法被"public"修饰

    image

    对比源代码中可以发现greeting方法的修饰符为"public"相匹配

    public class ClassStructureMethod {
        public  void greeting() throws Exception {
           try {
               int a=1;
               int b=1;
               int c=a+b;
               System.out.println(c);
           }catch (Exception e){
               System.out.println("catch");
           }finally {
               System.out.println("finally");
           }
        }
    }
    
    4.2 方法名称(name_index)

    Java虚拟机规范中方法名称用2个字节(u2)用来表示。可以换算成为一个整数,这个整数是常量池数组的一个下标,指向中一个CONSTANT_Utf8_info类型的常量用来描述方法的名称。

    示例方法名称

    方法名用2位字节(u2)来描述,对应16进制0x0011,即十进制的17,17是常量池数组的一个下标,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Utf8_info类型的常量(下标#17),对应字符串"greeting",表示方法名称

    image
    4.3 方法描述符(descriptor_index)

    按照Java虚拟机规范方法描述符用2位字节(u2)来描述,可以换算成为一个整数,这个整数是常量池数组的一个下标,指向中一个CONSTANT_Utf8_info类型的常量用来描述方法描述符。

    关于方法的描述符在常量池中讲过主要用来描述方法的参数和返回类型。

    示例中方法描述符

    方法修饰符用2个字节(u2)描述,对应16进制0x000B,即十进制的11,11是常量池数组的一个下标,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Utf8_info类型的常量(下标#11),对应字符串"()V",表示greeting方法不需要传递参数,且不需要返回值

    image

    4.4 方法中的属性

    4.4.1 属性表

    属性表(attribute_info)作用于Class文件、字段表、方法表。它们都可以携带自己的属性集合,用于描述某些场景专有的信息。

    4.4.2 虚拟机规范中定义属性表类型
    image
    4.4.3 属性表集合的结构

    属性表集合的结构被划分为属性表数量属性表集合。

    属性表数量(methods_count):表示方法中定义的属性个数。

    属性表(method_info):表示方法中定义某一个属性。其中涵盖了属性的所有信息。

    4.4.4 用于方法中属性表

    对于方法来说常用到的属性有如下几种:"code","Exception","Deprecated","Synthetic"。

    • code:用来表示方法中java字节码

    • Exception:用来记录方法中的异常信息。

    • Deprecated:用来表示方法是否被@Deprecated修饰

    • Synthetic:表示方法是否被编译器自动生成。

    4.4.5 属性表通用格式

    属性名称索引:属性名称索引占用2个字节,可以换算成为一个整数,这个整数是常量池数组的一个下标,指向中一个CONSTANT_Utf8_info类型的常量用来描述属性名称。通过属性名称就可以确定属性表类型

    属性长度:占用4个字节,它的值表示紧跟其后的多少个字节是拿来表示这个属性信息的。

    属性值:由若个个字节构造,字节的大小取决属性的长度

    image

    4.5 属性表数量

    Java虚拟机规范中属性表数量用2个字节(u2)用来表示。

    示例中属性表数量

    示例中属性表,对应16进制0x0002,即十进制的2,代表方法中有2个属性。

    image

    4.6 属性表

    4.6.1 Code属性
    4.6.1.1 Code属性名称索引

    属性名称索引用2个字节(u2)描述,对应16进制0x000C,即十进制的12,12是常量池数组的一个下标,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Utf8_info类型的常量(下标#12),对应字符串"code",表示当前属性code类型的属性。

    image
    4.6.1.2 Code属性结构

    通过属性名称索引知道了方法的第一个索引名称为"code".其虚拟机规范中的定义如下:

    image
    • attribute_name_index,属性名称索引,占有2个字节,其内的值指向了常量池中的某一项,该项表示字符串“Code”;
    • attribute_length,属性长度,占有 4个字节,其内的值表示后面有多少个字节是属于此Code属性表的;
    • max_stack,操作数栈深度的最大值,占有 2 个字节,在方法执行的任意时刻,操作数栈都不应该超过这个值,虚拟机的运行的时候,会根据这个值来设置该方法对应的栈帧(Stack Frame)中的操作数栈的深度;
    • max_locals,最大局部变量数目,占有 2个字节,其内的值表示局部变量表所需要的存储空间大小;
    • code_length,Java字节码的长度,占有 4 个字节,表示跟在其后的多少个字节表示的是机器指令;
    • code,Java字节码,该区域占有的字节数目由 code_length中的值决定。JVM最底层的要执行的Java字节码指令就存储在这里;
    • exception_table_length,显式异常表长度,占有2个字节,如果在方法代码中出现了try{} catch()形式的结构,该值不会为空,紧跟其后会跟着若干个exception_table结构体,以表示异常捕获情况;
    • exception_table,显式异常表,占有8 个字节,start_pc,end_pc,handler_pc中的值都表示的是PC计数器中的指令地址。exception_table表示的意思是:如果字节码从第start_pc行到第end_pc行之间出现了catch_type所描述的异常类型,那么将跳转到handler_pc行继续处理。
    • attribute_count,属性计数器,占有 2 个字节,表示Code属性表的其他属性的数目
    • attribute_info,表示Code属性表具有的属性表,它主要分为两个类型的属性表:“LineNumberTable”类型和“LocalVariableTable”类型。
    • “LineNumberTable”类型的属性表记录着Java源码和机器指令之间的对应关系
    • “LocalVariableTable”类型的属性表记录着局部变量描述
    4.6.1.3 Code属性长度

    属性长度索引用4个字节(u4)描述,对应16进制0x000000EB,即十进制的235,表示属性的长度占用235个字节

    image
    4.6.1.4 Code属性max_stack

    操作数栈深度的最大值用2个字节(u2)描述,对应16进制0x002,即十进制的2,表示方法中操作数栈深度最大值为2

    image
    4.6.1.5 Code属性max_locals

    最大局部变量数目用2个字节(u2)描述,对应16进制0x005,即十进制的5,表示最大局部变量数目为5

    image
    4.6.1.6 Code属性code_length

    java字节码的长度用4个字节(u4)描述,对应16进制0x0000003C,即十进制的60,表示ava字节码的长度为60

    image
    4.6.1.7 Code属性code

    java字节码的长度用60个字节描述

    image
    4.6.1.8 Code属性中异常表集合

    异常表集合的结构被划分为异常表数量异常表集合。

    异常表数量(exceptions_count):表示方法代码中可能存在抛出异常个数。

    异常表(exception_info):表示代码中一个异常。

    4.6.1.8.1 Code属性中异常表数量

    Code属性中异常表数量用2个字节(u2)描述,对应16进制0x004,即十进制的4,表示异常表数量为4

    image
    4.6.1.8.2 Code属性中异常表结构

    异常表用来表示的意思是:如果字节码从第start_pc行到第end_pc行之间出现了catch_type所描述的异常类型,那么将跳转到handler_pc行继续处理

    名称 字节长度 含义
    start_pc 2个字节 异常发生起始字节指令行
    end_pc 2个字节 异常发生结束字节指令行
    handler_pc 2个字节 异常处理字节指令行
    catch_type 2个字节 异常类型
    • 异常发生起始字节指令行用2个字节(u2)描述,对应16进制0x0000,即十进制的0,表示异常发生起始字节指令行为0

    • 异常发生结束字节指令行用2个字节(u2)描述,对应16进制0x000f,即十进制的15,表示异常发生结束字节指令行为15

    • 异常处理字节指令行用2个字节(u2)描述,对应16进制0x001A,即十进制的26,表示异常处理字节指令行为26

    • 异常类型用2个字节(u2)描述,对应16进制0x0006,即十进制的6,6是常量池数组的一个下标,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Utf8_info类型的常量(下标#6),对应字符串"java/lang/Exception"

    image

    这里同样可以使用javap反编译工具来解析获取。我们在此比对下,需要注意的是这里行表示的是反编译工具中字节指令的行而非源代码中的行

           stack=2, locals=5, args_size=1
             0: iconst_1
             1: istore_1
             2: iconst_1
             3: istore_2
             4: iload_1
             5: iload_2
             6: iadd
             7: istore_3
             8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            11: iload_3
            12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
            15: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            18: ldc           #4                  // String finally
            20: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            23: goto          59
            26: astore_1
            27: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            30: ldc           #7                  // String catch
            32: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            35: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            38: ldc           #4                  // String finally
            40: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            43: goto          59
            46: astore        4
            48: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            51: ldc           #4                  // String finally
            53: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            56: aload         4
            58: athrow
            59: return
          Exception table:
             from    to  target type
                 0    15    26   Class java/lang/Exception
                 0    15    46   any
                26    35    46   any
                46    48    46   any
    

    对比源代码

    public class ClassStructureMethod {
        public  void greeting() throws Exception {
           try {
               int a=1;
               int b=1;
               int c=a+b;
               System.out.println(c);
           }catch (Exception e){
               System.out.println("catch");
           }finally {
               System.out.println("finally");
           }
        }
    }
    

    code属性其他异常如下

    image
    4.6.1.9 Code属性中的属性

    code属性内部同样有属性集合

    属性表集合的结构同样被划分为属性表数量和属性表集合。

    属性表数量(methods_count):表示方法中定义的属性个数。

    属性表(method_info):表示方法中定义某一个属性。其中涵盖了属性的所有信息。

    4.6.1.9.1 Code属性中属性类型

    Code属性中定义的属性主要有“LineNumberTable”类型和“LocalVariableTable”类型

    • “LineNumberTable”类型的属性表记录着Java源码和机器指令之间的对应关系
    • “LocalVariableTable”类型的属性表记录着局部变量描述
    4.6.1.9.2 Java虚拟机定义的LineNumberTable
    image
    • attribute_name_index,属性名称索引,占有2个字节,其内的值指向了常量池中的某一项,该项表示字符串“LineNumberTable”;

    • attribute_length,属性长度,占有 4个字节,其内的值表示后面有多少个字节是属于此LineNumberTable属性表的;

    • line_number_table_length:描述line_number_table结构的数量

    • line_number_table:用来描述一行Java源码和机器指令之间的对应关系

    line_number_table结构

    名称 字节长度 含义
    start_pc 2个字节 字节码行号
    line_number 2个字节 java 源码行号
    4.6.1.9.3 Java虚拟机定义的LocalVariableTable

    [图片上传失败...(image-2d7657-1564563120952)]%20%E5%B1%9E%E6%80%A7.png)

    • attribute_name_index,属性名称索引,占有2个字节,其内的值指向了常量池中的某一项,该项表示字符串“LocalVariableTable”;

    • attribute_length,属性长度,占有 4个字节,其内的值表示后面有多少个字节是属于此LineNumberTable属性表的;

    • local_variable_table_length:描述local_variable_table结构的数量

    • local_variable_table:项目代表了一个栈帧与源码中的局部变量的关联

    local_variable_table结构

    image
    • start_pc 和 length 属性:分别代表了 这个局部变量的生命周期开始的字节码偏移量及其作用范围长度,两者结合起来就是这个局部变量在字节码中的作用域范围;

    • name_index 和 desc_index: 都是指向常量池中 CONSTANT_Utf8_info 型常量的索引,分别代表了局部变量的名称以及这个局部变量的描述符;

    • index:是这个局部变量在栈帧局部变量表中Slot的位置。当这个变量是 64 位类型时,它占用的Slot 为 index and index + 1;

    • LocalVariableTable属性:它增加了一个姐妹属性——LocalVariableTypeTable,这个新增的属性结构与LocalVariableTable 非常相似,仅仅是把记录的字段描述符的desc_index 替换为字段的特征签名,对于非泛型类型来说, 描述符和特征签名能描述的信息是基本一致的,但是泛型引入后,由于描述符中泛型的参数化类型被擦除掉,描述符就不能正确地描述泛型类型了,所以就引入了LocalVariableTypeTable了;

    如果不太理解可以看下图

    image
    4.6.1.9.4 Javap反编译结果
     LineNumberTable:
            line 6: 0
            line 7: 2
            line 8: 4
            line 9: 8
            line 13: 15
            line 14: 23
            line 10: 26
            line 11: 27
            line 13: 35
            line 14: 43
            line 13: 46
            line 15: 59
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                2      13     1     a   I
                4      11     2     b   I
                8       7     3     c   I
               27       8     1     e   Ljava/lang/Exception;
                0      60     0  this   Ljvm/ClassStructureMethod;
    
    4.6.2 Exceptions 属性

    Exception属性是在方法表中与Code属性平级的一项属性,切勿与Code属性中的异常混淆。Exception属性的作用是列举出方法中可能抛出的受查异常(Checked Exception),也就是方法描述时在 throws 关键字后面列举的异常。

    Java虚拟机定义的Exceptions

    image
    • attribute_name_index,属性名称索引,占有2个字节,其内的值指向了常量池中的某一项,该项表示字符串“Exceptions”;

    • attribute_length,属性长度,占有 4个字节,其内的值表示后面有多少个字节是属于此Exceptions属性表的;

    • number_of_exception:描述方法中可能抛出的受查异常的数量

    • exception_index_table:表示异常的名称索引,其内的值指向了常量池中的某一项,该项表示字符串对应异常的名称;

    示例中Exceptions属性

    image
    • 属性名称索引用2位字节(u2)来描述,对应16进制0x001B,即十进制的27,27是常量池数组的一个下标,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Utf8_info类型的常量(下标#27),字符串值为"Exceptions",表示属性类型为"Exceptions"。

    • 属性长度用4位字节(u4)来描述,对应16进制0x00000004,即十进制的4,表示"Exceptions"属性值长度为4个字节

    • 异常数量用2位字节(u2)来描述,对应16进制0x0001,即十进制的1,表示异常的数量为1

    • 异常的名称索引用2位字节(u2)来描述,对应16进制0x0006,即十进制的6,8是常量池数组的一个下标,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Class_info类型的常量(下标#6),CONSTANT_Class_info类型常量其值转换为整数37,指向常量池中一个常量,通过对照javap中结果中对应到一个CONSTANT_Utf8_info类型的常量(下标#37),字符串值为"java/lang/Exception"。

    4 总结

    可以用一张图来描述上诉方法的结构

    image

    javap完整结果

    Classfile /C:/work/project/juc-in-action/target/classes/jvm/ClassStructureMethod.class
      Last modified 2019-7-30; size 861 bytes
      MD5 checksum c291986bf1b6bc3997d2e13aff91e614
      Compiled from "ClassStructureMethod.java"
    public class jvm.ClassStructureMethod
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #9.#30         // java/lang/Object."<init>":()V
       #2 = Fieldref           #31.#32        // java/lang/System.out:Ljava/io/PrintStream;
       #3 = Methodref          #33.#34        // java/io/PrintStream.println:(I)V
       #4 = String             #35            // finally
       #5 = Methodref          #33.#36        // java/io/PrintStream.println:(Ljava/lang/String;)V
       #6 = Class              #37            // java/lang/Exception
       #7 = String             #38            // catch
       #8 = Class              #39            // jvm/ClassStructureMethod
       #9 = Class              #40            // java/lang/Object
      #10 = Utf8               <init>
      #11 = Utf8               ()V
      #12 = Utf8               Code
      #13 = Utf8               LineNumberTable
      #14 = Utf8               LocalVariableTable
      #15 = Utf8               this
      #16 = Utf8               Ljvm/ClassStructureMethod;
      #17 = Utf8               greeting
      #18 = Utf8               a
      #19 = Utf8               I
      #20 = Utf8               b
      #21 = Utf8               c
      #22 = Utf8               e
      #23 = Utf8               Ljava/lang/Exception;
      #24 = Utf8               StackMapTable
      #25 = Class              #37            // java/lang/Exception
      #26 = Class              #41            // java/lang/Throwable
      #27 = Utf8               Exceptions
      #28 = Utf8               SourceFile
      #29 = Utf8               ClassStructureMethod.java
      #30 = NameAndType        #10:#11        // "<init>":()V
      #31 = Class              #42            // java/lang/System
      #32 = NameAndType        #43:#44        // out:Ljava/io/PrintStream;
      #33 = Class              #45            // java/io/PrintStream
      #34 = NameAndType        #46:#47        // println:(I)V
      #35 = Utf8               finally
      #36 = NameAndType        #46:#48        // println:(Ljava/lang/String;)V
      #37 = Utf8               java/lang/Exception
      #38 = Utf8               catch
      #39 = Utf8               jvm/ClassStructureMethod
      #40 = Utf8               java/lang/Object
      #41 = Utf8               java/lang/Throwable
      #42 = Utf8               java/lang/System
      #43 = Utf8               out
      #44 = Utf8               Ljava/io/PrintStream;
      #45 = Utf8               java/io/PrintStream
      #46 = Utf8               println
      #47 = Utf8               (I)V
      #48 = Utf8               (Ljava/lang/String;)V
    {
      public jvm.ClassStructureMethod();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 3: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       5     0  this   Ljvm/ClassStructureMethod;
    
      public void greeting() throws java.lang.Exception;
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=5, args_size=1
             0: iconst_1
             1: istore_1
             2: iconst_1
             3: istore_2
             4: iload_1
             5: iload_2
             6: iadd
             7: istore_3
             8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            11: iload_3
            12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
            15: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            18: ldc           #4                  // String finally
            20: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            23: goto          59
            26: astore_1
            27: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            30: ldc           #7                  // String catch
            32: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            35: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            38: ldc           #4                  // String finally
            40: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            43: goto          59
            46: astore        4
            48: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            51: ldc           #4                  // String finally
            53: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            56: aload         4
            58: athrow
            59: return
          Exception table:
             from    to  target type
                 0    15    26   Class java/lang/Exception
                 0    15    46   any
                26    35    46   any
                46    48    46   any
          LineNumberTable:
            line 6: 0
            line 7: 2
            line 8: 4
            line 9: 8
            line 13: 15
            line 14: 23
            line 10: 26
            line 11: 27
            line 13: 35
            line 14: 43
            line 13: 46
            line 15: 59
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                2      13     1     a   I
                4      11     2     b   I
                8       7     3     c   I
               27       8     1     e   Ljava/lang/Exception;
                0      60     0  this   Ljvm/ClassStructureMethod;
          StackMapTable: number_of_entries = 3
            frame_type = 90 /* same_locals_1_stack_item */
              stack = [ class java/lang/Exception ]
            frame_type = 83 /* same_locals_1_stack_item */
              stack = [ class java/lang/Throwable ]
            frame_type = 12 /* same */
        Exceptions:
          throws java.lang.Exception
    }
    SourceFile: "ClassStructureMethod.java"
    
    

    相关文章

      网友评论

          本文标题:Java虚拟机-Class文件结构之方法表

          本文链接:https://www.haomeiwen.com/subject/aymtdctx.html