午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

深入理解Java Class文件格式(七)

 看風(fēng)景D人 2016-10-07


本專欄列前面的一系列博客, 對(duì)Class文件中的一部分?jǐn)?shù)據(jù)項(xiàng)進(jìn)行了介紹。 本文將會(huì)繼續(xù)介紹class文件中未講解的信息。 先回顧一下上面一篇文章。 在上一篇博客中, 我們介紹了:

  • this_class    對(duì)當(dāng)前類的描述
  • super_class    對(duì)當(dāng)前類的超類的描述
  • interfaces_count    當(dāng)前類直接實(shí)現(xiàn)的接口的數(shù)量或當(dāng)前接口直接繼承的接口的數(shù)量
  • interfaces  對(duì)當(dāng)前類或當(dāng)前接口直接實(shí)現(xiàn)或繼承的所有接口的描述


詳細(xì)信息請(qǐng)移步至上一篇博客 深入理解Java Class文件格式(六)。 更多關(guān)于Java Class文件和JVM的文章請(qǐng)關(guān)注我的專欄深入理解Java語(yǔ)言 。 


下面繼續(xù)介紹class文件中的其他信息。


class文件中的fields_count和fields


fields_count描述的是當(dāng)前的類中定義的字段的個(gè)數(shù), 注意, 這里包括靜態(tài)字段, 但不包括從父類繼承的字段。 如果當(dāng)前class文件是由一個(gè)接口生成的, 那么這里的fields_count描述的是接口中定義的字段, 我們知道, 接口中定義的字段默認(rèn)都是靜態(tài)的。此外要說(shuō)明的是, 編譯器可能會(huì)自動(dòng)生成字段, 也就是說(shuō), class文件中的字段的數(shù)量可能多于源文件中定義的字段的數(shù)量。 舉例來(lái)說(shuō), 編譯器會(huì)為內(nèi)部類增加一個(gè)字段, 這個(gè)字段是指向外圍類的對(duì)象的引用。
 
位于fields_count下面的數(shù)據(jù)叫做fields, 可以把它看做一個(gè)數(shù)組, 數(shù)組中的每一項(xiàng)是一個(gè)field_info 。這個(gè)數(shù)組中一共有fields_count個(gè)field_info , 每個(gè)field_info都是對(duì)一個(gè)字段的描述。 下面我們?cè)敿?xì)講解field_info的結(jié)構(gòu)。 每個(gè)field_info的結(jié)構(gòu)如下:


(1)access_flags

 其中access_flags占兩個(gè)字節(jié), 描述的是字段的訪問(wèn)標(biāo)志信息。 這里就不在詳細(xì)介紹了, 下面給出一張表格(該表格來(lái)自《深入Java虛擬機(jī)》):


標(biāo)志位名稱 含義 設(shè)定者
ACC_PUBLIC 0x0001 字段被設(shè)為public 類和接口
ACC_PRIVATE 0x0002 字段被設(shè)為private
ACC_PROTECTED 0x0004 字段被設(shè)為protected
ACC_STATIC 0x0008 字段被設(shè)為static 類和接口
ACC_FINAL 0x0010 字段被設(shè)為final 類和接口
ACC_VOLATILE 0x0040 字段被設(shè)為volatile
ACC_TRANSIENT 0x0080 字段被設(shè)為transient



(2)name_index

access_flags下面的兩個(gè)字節(jié)是name_index, 這是一個(gè)指向常量池的索引, 它描述的是當(dāng)前字段的字段名。 這個(gè)索引指向常量池中的一個(gè)CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)。 這個(gè)CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)中存放的字符串就是當(dāng)前字段的字段名。 


(3)descriptor_index

name_index下面的兩個(gè)字節(jié)叫做descriptor_index , 它同樣是一個(gè)指向常量池的索引, 它描述的是當(dāng)前字段的描述符。 這個(gè)索引指向常量池中的一個(gè)CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)。 這個(gè)CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)中存放的字符串就是當(dāng)前字段的描述符(關(guān)于字段描述符, 在前面的博客中已經(jīng)有過(guò)詳細(xì)的講解, 如果不明白, 請(qǐng)參考前面的博客:深入理解Java Class文件格式(二))。 


(4)attributes_count和attributes

descriptor_index 下面是attributes_count和attributes 。 這是對(duì)當(dāng)前字段所具有的屬性的描述。 這里的屬性和源文件中的屬性不是同一個(gè)概念, 在源文件測(cè)層面中, 屬性是字段的另一種叫法, 希望讀者不要疑惑。讀者也不要輕視class文件中的屬性, 這些屬性可以描述很多的信息。 我們會(huì)在后面的文章中進(jìn)行介紹。 

attributes_count表示這個(gè)字段有幾個(gè)屬性。attributes 可以看成一個(gè)數(shù)組, 數(shù)組中的每一項(xiàng)都是一個(gè)attribute_info , 每個(gè)attribute_info 表示一個(gè)屬性, 數(shù)組中一共有attributes_count個(gè)屬性??梢猿霈F(xiàn)在filed_info中的屬性有三種, 分別是ConstantValue, Deprecated, 和 Synthetic。 這些屬性會(huì)在后面的文章中進(jìn)行介紹。


下面我們以代碼的形式進(jìn)行解釋, 源碼如下:

  1. package com.jg.zhang;  
  2.   
  3. public class Programer extends Person{  
  4.   
  5.       
  6.     private Computer computer;  
  7.       
  8.     public Programer(Computer computer){  
  9.         this.computer = computer;  
  10.     }  
  11.       
  12.     public void doWork(){  
  13.         computer.calculate();  
  14.     }  
  15. }  


反編譯之后, 常量池中會(huì)有如下信息(這里省略了大部分無(wú)關(guān)信息):

  1. Constant pool:  
  2.   
  3. .........  
  4. .........  
  5.   
  6.    #5 = Utf8               computer  
  7.    #6 = Utf8               Lcom/jg/zhang/Computer;  
  8.   
  9. .........  
  10. .........  
  11.   
  12. {  
  13.   
  14.   private com.jg.zhang.Computer computer;  
  15.     flags: ACC_PRIVATE  
  16.   
  17. .........  
  18. .........  
  19.   
  20. }  

從反編譯的結(jié)果可以看出, 源文件中定義了一個(gè)Computer類型的字段computer, 并且是private的。 然后常量池中有這個(gè)字段的字段名和描述符。 其中常量池第五項(xiàng)的CONSTANT_Utf8_info是字段名, 第六項(xiàng)的CONSTANT_Utf8_info是該字段的描述符。這里有一點(diǎn)需要說(shuō)明, 在反編譯Programer.class時(shí),由于computer是私有的, 要加- private選項(xiàng), 否則的話, 雖然常量池中有字段引用信息, 但是不會(huì)輸出字段信息, 即下面這兩行不會(huì)輸出:
  1. private com.jg.zhang.Computer computer;  
  2.   flags: ACC_PRIVATE  

如果在javap中加入 - private選項(xiàng), 那么就會(huì)有上面兩行的輸出。 使用的命令如下:

  1. javap -c -v -private -classpath . com.jg.zhang.Programer  

 根據(jù)反編譯的結(jié)果,可以下面給出示意圖, 該圖說(shuō)明了與computer相對(duì)應(yīng)的field_info是不合引用常量池的 ( 其中虛線范圍內(nèi)表示常量池):





class文件中的methods_count和methods


fields下面的信息是methods_count和methods 。 methods_count描述的是當(dāng)前的類中定義的方法的個(gè)數(shù), 注意, 這里包括靜態(tài)方法, 但不包括從父類繼承的方法。 如果當(dāng)前class文件是由一個(gè)接口生成的, 那么這里的methods_count描述的是接口中定義的抽象方法的數(shù)量, 我們知道, 接口中定義的方法默認(rèn)都是公有的。此外需要說(shuō)明的是, 編譯器可能會(huì)在編譯時(shí)向class文件增加額外的方法, 也就是說(shuō), class文件中的方法的數(shù)量可能多于源文件中由用戶定義的方法。 舉例來(lái)說(shuō): 如果當(dāng)前類沒有定義構(gòu)造方法, 那么編譯器會(huì)增加一個(gè)無(wú)參數(shù)的構(gòu)造函數(shù)<init>; 如果當(dāng)前類或接口中定義了靜態(tài)變量, 并且使用初始化表達(dá)式為其賦值, 或者定義了static靜態(tài)代碼塊, 那么編譯器在編譯的時(shí)候會(huì)默認(rèn)增加一個(gè)靜態(tài)初始化方法<clinit> 。 
 
位于methods_count下面的數(shù)據(jù)叫做methods , 可以把它看做一個(gè)數(shù)組, 數(shù)組中的每一項(xiàng)是一個(gè)method_info 。這個(gè)數(shù)組中一共有methods_count個(gè)method_info , 每個(gè)method_info 都是對(duì)一個(gè)方法的描述。 下面我們?cè)敿?xì)講解method_info 的結(jié)構(gòu)。 每個(gè)method_info 的結(jié)構(gòu)如下, 幾乎和field_info的結(jié)構(gòu)是一樣的:

(1)access_flags

 其中access_flags占兩個(gè)字節(jié), 描述的是方法的訪問(wèn)標(biāo)志信息。 這里就不在詳細(xì)介紹了, 下面給出一張表格(該表格來(lái)自《深入Java虛擬機(jī)》):

標(biāo)志位名稱 標(biāo)志值 設(shè)定含義 設(shè)定者
ACC_PUBLIC 0x0001 方法設(shè)為public 類和接口
ACC_PRIVATE 0x0002 方法設(shè)為private
ACC_PROTECTED 0x0004 方法設(shè)為protected
ACC_STATIC 0x0008 方法設(shè)為static
ACC_FINAL 0x0010 方法設(shè)為final
ACC_SYNCHRONIZED 0x0020 方法設(shè)為sychronized
ACC_NATIVE 0x0100 方法設(shè)為native
ACC_ABSTRACT 0x0400 方法設(shè)為abstract 類和接口
ACC_STRICT 0x0800 方法設(shè)為strictFP 類和接口的<clinit>方法


(2)name_index

access_flags下面的兩個(gè)字節(jié)是name_index, 這是一個(gè)指向常量池的索引, 它描述的是當(dāng)前方法的方法名。 這個(gè)索引指向常量池中的一個(gè)CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)。 這個(gè)CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)中存放的字符串就是當(dāng)前方法的方法名。 


(3)descriptor_index

name_index下面的兩個(gè)字節(jié)叫做descriptor_index , 它同樣是一個(gè)指向常量池的索引, 它描述的是當(dāng)前方法的描述符。 這個(gè)索引指向常量池中的一個(gè)CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)。 這個(gè)CONSTANT_Utf8_info數(shù)據(jù)項(xiàng)中存放的字符串就是當(dāng)前方法的描述符(關(guān)于方法描述符, 在前面的博客中已經(jīng)有過(guò)詳細(xì)的講解, 如果不明白, 請(qǐng)參考前面的博客: 深入理解Java Class文件格式(二))。 


(4)attributes_count和attributes

descriptor_index 下面是attributes_count和attributes 。 這是對(duì)當(dāng)前方法所具有的屬性的描述。 這里的屬性和源文件中的屬性不是同一個(gè)概念, 在源文件測(cè)層面中, 屬性是字段的另一種叫法, 希望讀者不要疑惑。讀者也不要輕視class文件中的屬性, 這些屬性可以描述很多的信息。 我們會(huì)在后面的文章中進(jìn)行介紹。 

attributes_count表示這個(gè)字段有幾個(gè)屬性。attributes 可以看成一個(gè)數(shù)組, 數(shù)組中的每一項(xiàng)都是一個(gè)attribute_info , 每個(gè)attribute_info 表示一個(gè)屬性, 數(shù)組中一共有attributes_count個(gè)屬性??梢猿霈F(xiàn)在method_info 中的屬性有三種, 分別是Code, Deprecated, Exceptions 和Synthetic。 在這幾個(gè)屬性中, 尤其是Code和Exceptions 非常重要, 這兩個(gè)屬性對(duì)于在class文件中完整描述一個(gè)方法起著至關(guān)重要的作用, 其中Code屬性中存放方法的字節(jié)面指令,Exceptions 屬性是對(duì)方法聲明中拋出的異常的描述 。 這兩屬性以及其他一些屬性, 會(huì)在下一篇文章中詳細(xì)介紹, 敬請(qǐng)關(guān)注。


介紹完了每個(gè)method_info的結(jié)構(gòu), 下面我們以代碼來(lái)說(shuō)明, 還是使用上面的源碼:

  1. package com.jg.zhang;  
  2.   
  3. public class Programer extends Person{  
  4.   
  5.       
  6.     private Computer computer;  
  7.       
  8.     public Programer(Computer computer){  
  9.         this.computer = computer;  
  10.     }  
  11.       
  12.     public void doWork(){  
  13.         computer.calculate();  
  14.     }  
  15. }  

反編譯之后, 常量池中會(huì)有如下信息(這里省略了大部分無(wú)關(guān)信息):

  1. Constant pool:  
  2.   
  3. .........  
  4.   
  5.    #7 = Utf8               <init>  
  6.    #8 = Utf8               (Lcom/jg/zhang/Computer;)V  
  7.   
  8. .........  
  9.   
  10.   #12 = Utf8               ()V  
  11.   
  12. .........  
  13.   
  14.   #19 = Utf8               doWork  
  15.   
  16. {  
  17.   
  18. .........  
  19.   
  20.   public com.jg.zhang.Programer(com.jg.zhang.Computer);  
  21.     flags: ACC_PUBLIC  
  22.   
  23. .........  
  24.   
  25.   public void doWork();  
  26.     flags: ACC_PUBLIC  
  27.   
  28. .........  
  29. }  

由反編譯結(jié)果可以看出, 該類中定義了兩個(gè)方法, 其中一個(gè)是構(gòu)造方法, 一個(gè)是doWork方法, 且這兩個(gè)方法都是public的。 這兩個(gè)方法的描述信息都存放在常量池。 其中第7項(xiàng)的CONSTANT_Utf8_info為構(gòu)造方法的方法名, 第8項(xiàng)的CONSTANT_Utf8_info為構(gòu)造方法的方法描述符, 第19項(xiàng)的CONSTANT_Utf8_info為doWork方法的方法名, 第12項(xiàng)的CONSTANT_Utf8_info為doWork方法的方法描述符。 

根據(jù)常量池中的信息, 可以得出如下的示意圖, 該示意圖形象的說(shuō)明了class文件中的method_info是如何引用常量池中的數(shù)據(jù)項(xiàng)來(lái)描述當(dāng)前類中定義的方法的。 圖中虛線范圍內(nèi)表示常量池所在的區(qū)域:




總結(jié)


到此為止, 我們就介紹完了class文件中的fields和methods, 進(jìn)行一下總結(jié)。 

 fields是對(duì)當(dāng)前類中定義的字段的描述, 其中每個(gè)字段使用一個(gè)field_info表示, fields中有fields_count個(gè)field_info。

methods是對(duì)當(dāng)前類或者接口中聲明的方法的描述, 其中每個(gè)方法使用一個(gè)method_info表示, methods中有methods_count個(gè)method_info。 

在下一篇博客中, 將會(huì)介紹class文件中的各個(gè)屬性, 敬請(qǐng)關(guān)注。




更多關(guān)于深入理解Java的文章, 請(qǐng)關(guān)注我的專欄 : http://blog.csdn.net/column/details/zhangjg-java-blog.html

更多關(guān)于Java和Android等其他技術(shù)的文章, 請(qǐng)關(guān)注我的博客: http://blog.csdn.net/zhangjg_blog





    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多