Java Class文件分析(二)——訪問標(biāo)志坝辫,類索引篷就,父類索引,接口索引集合近忙,字段集合竭业,方法表集合,屬性表集合

下面我們接著為訪問標(biāo)志及舍,類索引未辆,父類索引,接口索引集合击纬,字段集合鼎姐,方法表集合

訪問標(biāo)志:

常量池結(jié)束后緊接著的兩個(gè)字節(jié)代表訪問標(biāo)志,用來標(biāo)識一些類或接口的訪問信息更振,包括:這個(gè)Class是類還是接口炕桨;是否定義為public;是否定義為abstract肯腕;如果是類的話献宫,是否被聲明為final等。具體的標(biāo)志位以及含義如下表:

標(biāo)志名稱 標(biāo)志值 含義
ACC_PUBLIC 0x0001 是否是public
ACC_FINAL 0x0010 是否被聲明為final实撒,只有類可以設(shè)置
ACC_SUPER 0x0020 是否允許使用invokespecial字節(jié)碼指令的新語義姊途,JDK1.0.2之后編譯出來的類的這個(gè)標(biāo)志默認(rèn)為真
ACC_INTERFACE 0x0200 標(biāo)識是一個(gè)接口
ACC_ABSTRACT 0x0400 是否是abstract,對于接口和抽象類來說為真知态,其他類都為假
ACC_SYNITHETIC 0x1000 標(biāo)識這個(gè)類并非由用戶代碼產(chǎn)生
ACC_ANNOTATION 0x2000 標(biāo)識這是一個(gè)注解
ACC_ENUM 0x4000 標(biāo)識這是一個(gè)枚舉類

類索引(2個(gè)字節(jié))捷兰、父類索引(2個(gè)字節(jié))與接口索引(2個(gè)字節(jié)接口數(shù)+接口)集合:

在訪問標(biāo)志access_flags后接下來就是類索引(this_class)和父類索引(super_class),這兩個(gè)數(shù)據(jù)都是u2類型的负敏,而接下來的接口索引集合是一個(gè)u2類型的集合贡茅,class文件由這三個(gè)數(shù)據(jù)項(xiàng)來確定類的繼承關(guān)系。由于Java中是單繼承其做,所以父類索引只有一個(gè)顶考;但Java類可以實(shí)現(xiàn)多個(gè)接口,所以接口索引是一個(gè)集合妖泄。

類索引用來確定這個(gè)類的全限定名驹沿,這個(gè)全限定名就是說一個(gè)類的類名包含所有的包名,然后使用"/"代替"."蹈胡。比如Object的全限定名是java.lang.Object渊季。父類索引確定這個(gè)類的父類的全限定名朋蔫,除了Object之外,所有的類都有父類梭域,所以除了Object之外所有類的父類索引都不為0.接口索引集合存儲了implements語句后面按照從左到右的順序的接口斑举。

類索引和父類索引都是一個(gè)索引搅轿,這個(gè)索引指向常量池中的CONSTANT_Class_info類型的常量病涨。然后再CONSTANT_Class_info常量中的索引就可以找到常量池中類型為CONSTANT_Utf8_info的常量,而這個(gè)常量保存著類的全限定名璧坟。

字段表集合:

  • 字段表用來描述接口或類中聲明的變量既穆。字段包括類級變量和實(shí)例級變量,但不包括方法內(nèi)變量雀鹃。所謂的類級變量就是靜態(tài)變量幻工,這個(gè)變量不屬于這個(gè)類的任何實(shí)例,可以不用定義類實(shí)例就可以使用黎茎;實(shí)例級變量不是靜態(tài)變量囊颅,是和類實(shí)例相關(guān)聯(lián)的,需要定義類實(shí)例才能使用傅瞻。

  • 那么踢代,聲明一個(gè)變量需要哪些信息呢?
    有:字段的作用域(public嗅骄、private和protected修飾符)胳挎、是實(shí)例變量還是類變量(static修飾符)、可變性(final修飾符)溺森、并發(fā)可見性(volatile修飾符)慕爬、是否可被序列化(transient修飾符)、字段的數(shù)據(jù)類型(基本類型屏积、對象医窿、數(shù)組)以及字段名稱。包含的信息有點(diǎn)多炊林,不過不需要的可以不寫姥卢。這些信息中,各個(gè)修飾符可以用布爾值表示铛铁。而字段叫什么名字隔显、字段被定義為什么類型數(shù)據(jù)都是無法固定的,只能用常量池中的常量來表示饵逐。

下面是字段表的格式:

類型 名稱 數(shù)量
U2 access_flags 1
U2 name_index 1
U2 descriptor_index 1
U2 attributes_count 1
attribute_info attributes attributes_count

其中的字段修飾符access_flags括眠,和類中的access_flags類似,對于字段來說可以設(shè)置的標(biāo)志位及含義如下:

標(biāo)志名稱 標(biāo)志值 含義
ACC_PUBLIC 0x0001 字段是否是public
ACC_PRIVATE 0x0002 字段是否是private
ACC_PROTECTED 0x0004 字段是否是protected
ACC_STATIC 0x0008 字段是否是static
ACC_FINAL 0x0010 字段是否是final
ACC_VOLATILE 0x0040 字段是否是volatile
ACC_TRANSIENT 0x0080 字段是否是transient
ACC_SYNTHETIC 0x1000 字段是否是由編譯器自動產(chǎn)生的
ACC_ENUM 0x4000 字段是否是enum

顯然倍权,ACC_PUBLIC掷豺、ACC_PRIVATE和ACC_PROTECTED只能選擇一個(gè)捞烟,ACC_FINAL和ACC_VOLATILE不能同時(shí)選擇。接口中的字段必須有ACC_PUBLIC当船、ACC_STATIC和ACC_FINAL標(biāo)志题画,這是Java語言本身的規(guī)則決定的。

access_flags給出了字段中所有可以用布爾值表示的修飾符德频,剩下的信息就是字段的名字苍息、變量類型等信息。access_flags后面的是name_index和descriptor_index壹置,前者是字段名的常量池索引竞思,后者是字段描述符的常量池索引。name_index可以描述字段的名字钞护,descriptor_index可以描述字段的數(shù)據(jù)類型盖喷。不過,對于方法的描述符來說就要復(fù)雜一些难咕,因?yàn)橐粋€(gè)方法除了返回值類型课梳,還有參數(shù)類型,而且參數(shù)的個(gè)數(shù)還不確定余佃。根據(jù)描述符規(guī)則暮刃,這些類型都使用一個(gè)大寫字母來表示,如下表:

標(biāo)志名稱 含義 標(biāo)志名稱 含義
B byte J long
C char S short
D double Z boolean
F float V void
I int L 對象類型咙冗,如Ljava/lang/Object

對于數(shù)組類型沾歪,每一個(gè)維度將使用一個(gè)前置的“[”字符來描述。比如定義一個(gè)java.lang.String[][]類型的二維數(shù)組雾消,將記錄為"[[Ljava/lang/String"灾搏,一個(gè)double數(shù)組"double[]"將標(biāo)記為"[D"。

當(dāng)描述符用來描述方法時(shí)立润,按照先參數(shù)列表狂窑,后返回值的順序描述,參數(shù)列表按照參數(shù)的嚴(yán)格順序放在一組小括號"()"內(nèi)桑腮。比如方法void inc()的描述符是:()V泉哈。方法java.lang.String toString()的描述符是:()Ljava/lang/String。方法int indexOf(char[] source,int sourceOffset,int sourceCount,char[] target,int targetOffset,int targetCount,int fromIndex)的描述符是:([CII[CIII)I破讨。

descriptor_info后面是屬性信息丛晦,這會在后面屬性表集合中介紹。

方法表集合:

在字段表集合中介紹了字段的描述符和方法的描述符提陶,對于理解方法表有很大幫助烫沙。class文件存儲格式中對方法的描述和對字段的描述幾乎相同,方法表的結(jié)構(gòu)也和字段表相同隙笆,這里就不再列出锌蓄。不過升筏,方法表的訪問標(biāo)志和字段的不同,列出如下:

標(biāo)志名稱 標(biāo)志值 含義
ACC_PUBLIC 0x0001 方法是否是public
ACC_PRIVATE 0x0002 方法是否是private
ACC_PUBLICPROTECTED 0x0004 方法是否是protected
ACC_STATIC 0x0008 方法是否是static
ACC_FINAL 0x0010 方法是否是final
ACC_SYNCHRONIZED 0x0020 方法是否是synchronized
ACC_BRIDGE 0x0040 方法是否是由編譯器產(chǎn)生的橋接方法
ACC_VARARGS 0x0080 方法是否接受不定參數(shù)
ACC_NATIVE 0x0100 方法是否是native
ACC_ABSTRACT 0x0400 方法是否是abstract
ACC_STRICTFP 0x0800 方法是否是strictfp
ACC_SYNTHETIC 0x1000 方法是否是由編譯器自動產(chǎn)生的

下面我們來一個(gè)例子

JavaCode

public class Test{
    
    public int a;
    private String b;
    private int add(int arg1,int arg2){
        return arg1+arg2; 
    }
    
}

二進(jìn)制解析


image.png

Javap解析

C:\Users\GH\Desktop>javap -verbose Test.class
Classfile /C:/Users/GH/Desktop/Test.class
  Last modified 2018-8-8; size 287 bytes
  MD5 checksum 430dad91948d95b5532953a32356174c
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#16         // java/lang/Object."<init>":()V
   #2 = Class              #17            // Test
   #3 = Class              #18            // java/lang/Object
   #4 = Utf8               a
   #5 = Utf8               I
   #6 = Utf8               b
   #7 = Utf8               Ljava/lang/String;
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               add
  #13 = Utf8               (II)I
  #14 = Utf8               SourceFile
  #15 = Utf8               Test.java
  #16 = NameAndType        #8:#9          // "<init>":()V
  #17 = Utf8               Test
  #18 = Utf8               java/lang/Object
{
  public int a;
    descriptor: I
    flags: ACC_PUBLIC
 
  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 1: 0
}
SourceFile: "Test.java"

屬性表集合:

屬性表(attribute_info)瘸爽,在Class文件您访、字段表、方法表都可以攜帶字節(jié)的屬性表集合剪决,用于描述某些場景專有信息灵汪。

屬性名稱 使用位置 含義
Code 方法表 Java代碼編譯成的字節(jié)碼指令
ConstantValue 字段表 final關(guān)鍵字定義的常量池
Deprecated 類,方法昼捍,字段表 被聲明為deprecated的方法和字段
Exceptions 方法表 方法拋出的異常
EnclosingMethod 類文件 僅當(dāng)一個(gè)類為局部類或者匿名類是才能擁有這個(gè)屬性识虚,這個(gè)屬性用于標(biāo)識這個(gè)類所在的外圍方法
InnerClass 類文件 內(nèi)部類列表
LineNumberTable Code屬性 Java源碼的行號與字節(jié)碼指令的對應(yīng)關(guān)系
LocalVariableTable Code屬性 方法的局部便狼描述
StackMapTable Code屬性 JDK1.6中新增的屬性,供新的類型檢查檢驗(yàn)器檢查和處理目標(biāo)方法的局部變量和操作數(shù)有所需要的類是否匹配
Signature 類妒茬,方法表,字段表 用于支持泛型情況下的方法簽名
SourceFile 類文件 記錄源文件名稱
SourceDebugExtension 類文件 用于存儲額外的調(diào)試信息
Synthetic 類蔚晨,方法表乍钻,字段表 標(biāo)志方法或字段為編譯器自動生成的
LocalVariableTypeTable 使用特征簽名代替描述符,是為了引入泛型語法之后能描述泛型參數(shù)化類型而添加
RuntimeVisibleAnnotations 類铭腕,方法表银择,字段表 為動態(tài)注解提供支持
RuntimeInvisibleAnnotations 表,方法表累舷,字段表 用于指明哪些注解是運(yùn)行時(shí)不可見的
RuntimeVisibleParameterAnnotation 方法表 作用與RuntimeVisibleAnnotations屬性類似浩考,只不過作用對象為方法
RuntimeInvisibleParameterAnnotation 方法表 作用與RuntimeInvisibleAnnotations屬性類似,作用對象哪個(gè)為方法參數(shù)
AnnotationDefault 方法表 用于記錄注解類元素的默認(rèn)值
BootstrapMethods 類文件 用于保存invokeddynamic指令引用的引導(dǎo)方式限定符

對于每個(gè)屬性被盈,它的名稱需要從常量池中引用一個(gè)CONSTANT_utf8_info類型的常量類表示析孽,而屬性值的結(jié)構(gòu)則是完全自定義的,只需要通過一個(gè)u4的長度屬性區(qū)說明屬性值所占用的位數(shù)即可.

屬性表定義的結(jié)構(gòu):

類型 名稱 數(shù)量
u2 attribute_name_index 1
u2 attribute_length 1
u1 info attribute_length

1.CODE屬性
Java程序方法體中的代碼經(jīng)過Javac編譯處理后只怎,最終變?yōu)樽止?jié)碼指令存儲在Code屬性中.Code屬性出現(xiàn)在方法表的屬性集合中袜瞬,但是并非所有的方法表都有這個(gè)屬性.例如接口或類中的方法就不存在Code屬性了.
在字節(jié)碼指令之后的是方法的是方法的顯式異常處理表集合,異常表對于Code屬性來說并不是必須的.
結(jié)構(gòu):

類型 名稱 數(shù)量
u2 attribute_name_index 1
u4 attribute_length 1
u2 max_stack 1
u2 max_locals 1
u4 code_length 1
u1 code code_length
u2 exception_table_length 1
exception_info exception_table exception_length
u2 attributes_count 1
attribute_info attributes attributes_count

2.EXCEPTIONS屬性

  • Exception屬性的作用是列出方法中能拋出的受查異常Check Exceptions身堡,也就是方法描述時(shí)在throws關(guān)鍵字之后列舉的異常
  • Exception屬性中的number_of_exceptions項(xiàng)表示方法可能拋出的number_of_exceptions種受查異常邓尤,每一種受查異常使用一個(gè)exception_index_table項(xiàng)表示,exception_index_table是一個(gè)指向常量池中CONSTANT_Class_info型常量的索引贴谎,代表了該受查異常的類型.

結(jié)構(gòu):

類型 名稱 數(shù)量
u2 attribute_name_index 1
u2 attribute_lrngth 1
u2 attribute_of_exception 1
u2 exception_index_tsble number_of_exceptions

3.LINENUMBERTABLE屬性
line_number_table是一個(gè)數(shù)量為line_number_table_length汞扎,類型為line_number_info的集合,line_number_info表包括了start_PC和line_number兩個(gè)u2類型的數(shù)據(jù)項(xiàng)擅这,前者是字節(jié)碼行號澈魄,后者是Java源代碼行號.

結(jié)構(gòu):

類型 名稱 數(shù)量
u2 attribute_name_index 1
u4 attribute_length 1
u2 line_number_table_length 1
line_number_info line_number_table line_number_table_length

虛擬機(jī)預(yù)定義的屬性有20多個(gè),就不意一一介紹蕾哟,基本上和上述的幾個(gè)屬性差不多.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末一忱,一起剝皮案震驚了整個(gè)濱河市莲蜘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帘营,老刑警劉巖票渠,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異芬迄,居然都是意外死亡问顷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門禀梳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來杜窄,“玉大人,你說我怎么就攤上這事算途∪” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵嘴瓤,是天一觀的道長扫外。 經(jīng)常有香客問我,道長廓脆,這世上最難降的妖魔是什么筛谚? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮停忿,結(jié)果婚禮上驾讲,老公的妹妹穿的比我還像新娘。我一直安慰自己席赂,他們只是感情好吮铭,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氧枣,像睡著了一般沐兵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上便监,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天扎谎,我揣著相機(jī)與錄音,去河邊找鬼烧董。 笑死毁靶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的逊移。 我是一名探鬼主播预吆,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼胳泉!你這毒婦竟也來了拐叉?” 一聲冷哼從身側(cè)響起岩遗,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凤瘦,沒想到半個(gè)月后宿礁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蔬芥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年梆靖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笔诵。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡返吻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乎婿,到底是詐尸還是另有隱情测僵,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布次酌,位于F島的核電站恨课,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏岳服。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一希俩、第九天 我趴在偏房一處隱蔽的房頂上張望吊宋。 院中可真熱鬧,春花似錦颜武、人聲如沸璃搜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽这吻。三九已至,卻和暖如春篙议,著一層夾襖步出監(jiān)牢的瞬間唾糯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工鬼贱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留移怯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓这难,卻偏偏與公主長得像舟误,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子姻乓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361