JVM虛擬機-Class文件之字段表集合

一、概述

在接口索引集合後面 的就是字段表集合了。字段表(field_info)用於描述接口或者類中聲明的變量。字段包括類級變量以及實例級變量,但是不包括在方法內部聲明的局部變量。

二、字段表集合的構成

1.字段計數器

字段表集合是由很多field_info組成的,所以字段表集合的前兩個字節表示有多少個字段,佔兩個字節,16位。

2.field_info

每個field_info的結構如下表所示:

類型     名稱 數量
u2 access_flags 1
u2 name_index 1
u2 descriptor_index 1
u2 attributes_count 1
attribute_info attributes attributes_count

3.access_flags

access_flags爲字段修飾符,也稱字段訪問標誌。access_flag佔2個字節,16位,它與類中的access_flags項目是非常相似的,包括如下類型:

標誌名稱 標誌值 含義
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_VOLATILE 0x00 40 字段是否爲volatile
ACC_TRANSTENT 0x00 80 字段是否爲transient
ACC_SYNCHETIC 0x10 00 字段是否爲由編譯器自動產生
ACC_ENUM 0x40 00 字段是否爲enum

某個字段擁有哪些標誌符,就是要用訪問標識取|操作:

如0x0001|0x0008爲0x0009。

4.name_index和descriptor_index

name_index和descriptor_index,是對常量池的引用,name_index指字段的簡單名稱,descriptor_index指字段描述符。

descriptor_index描述符用來描述字段的數據類型,基本數據類型用一個大寫字符來表示,而對象類型則用字符加L加對象名的全限定名來表示。

標誌符 含義
B 基本數據類型byte
C 基本數據類型char
D 基本數據類型double
F 基本數據類型float
I 基本數據類型int
J 基本數據類型long
S 基本數據類型short
Z 基本數據類型boolean
V 基本數據類型void
L 對象類型

對數組類型,每一維將使用一個"["字符來描述.如一個Stirng[][]類型的二維數組,將被記錄爲:[[Ljava/lang/Stirng,一個整型數組"int []"將被記錄爲"[I"。

三、實例拆解

定義一個類:

public class HelloWord{
    
    public int i;
    private Long l;
    protected String[][] arrs;
    public Object test(){return null;}
}

 

javap -verbose HelloWord.class

public class com.csdn.reader.HelloWord
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#21         // java/lang/Object."<init>":()V
   #2 = Class              #22            // com/csdn/reader/HelloWord
   #3 = Class              #23            // java/lang/Object
   #4 = Utf8               i
   #5 = Utf8               I
   #6 = Utf8               l
   #7 = Utf8               Ljava/lang/Long;
   #8 = Utf8               arrs
   #9 = Utf8               [[Ljava/lang/String;
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               LocalVariableTable
  #15 = Utf8               this
  #16 = Utf8               Lcom/csdn/reader/HelloWord;
  #17 = Utf8               test
  #18 = Utf8               ()Ljava/lang/Object;
  #19 = Utf8               SourceFile
  #20 = Utf8               HelloWord.java
  #21 = NameAndType        #10:#11        // "<init>":()V
  #22 = Utf8               com/csdn/reader/HelloWord
  #23 = Utf8               java/lang/Object
{
  public int i;
    descriptor: I
    flags: ACC_PUBLIC

  protected java.lang.String[][] arrs;
    descriptor: [[Ljava/lang/String;
    flags: ACC_PROTECTED

  public com.csdn.reader.HelloWord();
    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   Lcom/csdn/reader/HelloWord;

  public java.lang.Object test();
    descriptor: ()Ljava/lang/Object;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aconst_null
         1: areturn
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       2     0  this   Lcom/csdn/reader/HelloWord;
}

四、總結

字段表集合中不會列出從父類或者父接口中繼承而來的字段,但有可能列出原來Java代碼中不存在的字段和方法,譬如在內部類中爲了保持對外部類的訪問性,會自動添加指向外部類實例的字段。

另外,在Java語言中字段是無法重載的,兩個字段的數據類型,修飾符不管是否相同,都必須使用不一樣的名稱,但是對於字節碼來講,如果連個字段的描述符不一致,那字段重名就是合法的。

參考資料:

  1. https://www.cnblogs.com/lrh-xl/p/5350612.html
  2. https://blog.csdn.net/xiaoqiu_cr/article/details/86726474
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章