(十七)方法表

方法表集合

  •    前面的魔数,次版本号,主板本号,常量池入口,常量池,访问标志,类索引,父类索引,接口索引集合,字段表集合,那么再接下来就是方法表了. 

 

  •   方法表的构造如同字段表一样,依次包括了访问标志(access_flags),名称索引(name_index),描述符索引(descriptor_index),属性表集合(attributes)几项.
  •   方法表结构:  
类型 名称 数量
u2 access_flags 1
u2 name_index 1
u2 descriptor_index 1
u2 attributes_count 1
attribute_info attributes attributes_cou  方法访问标志

标志名称 标志值 含义
ACC_PUBLIC 0x00 01 方法是否为public
ACC_PRIVATE 0x00 02 方法是否为private
ACC_PROTECTED 0x00 04 方法是否为protected
ACC_STATIC 0x00 08 方法是否为static
ACC_FINAL 0x00 10 方法是否为final
ACC_SYHCHRONRIZED 0x00 20 方法是否为synchronized
ACC_BRIDGE 0x00 40 方法是否是有编译器产生的方法
ACC_VARARGS 0x00 80 方法是否接受参数
ACC_NATIVE 0x01 00 方法是否为native
ACC_ABSTRACT 0x04 00 方法是否为abstract
ACC_STRICTFP 0x08 00 方法是否为strictfp
ACC_SYNTHETIC 0x10 00 方法是否是有编译器自动产生的

  方法里的Java代码,经过编译器编译成字节码指令后,存放在方法属性表集合中一个名为"Code"的属性里面,属性表作为calss文件格式中最具扩展的一种数据项目.

  在Java语言中,要重载一个方法,除了要与原方法具有相同的简单名称之外,还要求必须拥有一个与原方法不同的签名,特征签名就是一个方法中各个参数在常量池中的字段符号引用的集合,也就是因为返回值不会包含在特征签名中,因此Java语言里面是无法仅仅靠返回值的不同来堆一个已有方法进行重载的.但是在class文件格式中,特征签名的范围更大一些,只要描述符不是完全一致的两个方法也可以共存.也就是说,如果两个方法有相同的名称和特征签名,但是返回值不同,那么也是可以合法共存与同一个class文件中的.

 下面继续前面分析的CLASS文件

  代码

public class Test {

    private int getAge(int userId){
        return 10;
    }
    
    public Object getUserName(String sex,Object obj){
        return "admin";
    }
}

  javap分析的常量池:

C:UsersAdministratorDesktop>javap -verbose Test.class
Classfile /C:/Users/Administrator/Desktop/Test.class
  Last modified 2018-5-19; size 364 bytes
  MD5 checksum f8f46b81a72fa2dea893f30738c9bd8c
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#15         // java/lang/Object."<init>":()V
   #2 = String             #16            // admin
   #3 = Class              #17            // Test
   #4 = Class              #18            // java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               getAge
  #10 = Utf8               (I)I
  #11 = Utf8               getUserName
  #12 = Utf8               (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
  #13 = Utf8               SourceFile
  #14 = Utf8               Test.java
  #15 = NameAndType        #5:#6          // "<init>":()V
  #16 = Utf8               admin
  #17 = Utf8               Test
  #18 = Utf8               java/lang/Object
{
  public Test();
    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 2: 0

  public java.lang.Object getUserName(java.lang.String, java.lang.Object);
    descriptor: (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=3, args_size=3
         0: ldc           #2                  // String admin
         2: areturn
      LineNumberTable:
        line 9: 0
}
SourceFile: "Test.java"

  class文件分析:

  

  直接看方法表部分(有点乱),首先是右下角的methods_count:0x00 03表示方法集中有三个方法(加上构造方法正好三个).access_flags:0x00 01表示访问标志值为1,对应上面的方法访问标志表的public,在看源文件的方法确实是public.name_index:0x00 05表示方法的名称索引为5,对应上面的常量池5,为"<init>".decriptor_index:0x00 06代表描述符索引值为6,对应上面常量池的"()v".attributes_count:0x00 01代表此方法的属性表集合有一项属性,属性的名称索引为0x00 07,对应上面常量池7为"code ",说明此属性是方法的字节码描述,字节码描述下章节将讲解。

原文地址:https://www.cnblogs.com/shyroke/p/9058634.html