一、class檔案內容
註:每個java類只能有一個class檔案或介面,下面討論中u4表示4個位元組,u2表示2個位元組
class檔案內容如下:
- magic(魔數)-u4(u4表示4個位元組)
- 0xCAFEBABE,其作用在於可以輕鬆辨別出Java class檔案和非Java class檔案;
- minor_version-u2和major_version-u2(次、主要版本號)
- 對於虛擬機器來說,主次版本號碼確定了特定的class檔案格式,通常只有給定主要版本號和一系列次版本號碼後,虛擬機器才能讀取該class檔案;
- 如所示
第5、6位元組表示次版本號碼=0
第7、8位元組表示主要版本號=50(高位在前)
- constant_pool_count-u2和constant_pool(常量池)
- 常量池的數量為constant_pool_count-1,其索引從1開始;
- 除直接常量外,常量池還包括類和介面的全限定名、欄位的名稱和描述符以及方法的名稱和描述符等符號引用;
- 每個常量池入口都有一個位元組的標誌,這個標誌指出了列表中該位置的常量類型。虛擬機器擷取這個標誌後,就知道在標誌後面的常量類型了;其中每一個標誌都有一個相對應的表結構來描述該常量池;具體類型如下表所示:
- access_flags(訪問標誌)-u2
- this_class-u2(當前類)
- 它是一個對常量池的索引,在this_class位置的常量池入口必須為CONSTANT_Class類型對應的表結構CONSTANT_Class_info...;
- 顯示了常量池的使用方法:
在CONSTANT_Utf8_info表的bytes裡存放的即是當前類的全限定名字串;
- super_class-u2(直接超類)
- 和this_class表示的內容相同;
- 除了java.lang.Object類以外,常量池索引super_class對於所有類均有效;
- 對於java.lang.Object,其super_class為0;
- 對於介面,其super_class指向的常量池為java.lang.Object;
- interfaces_count-u2和interfaces(介面列表)
- 儲存該類直接實現或該介面所擴充的介面數量;
- 介面按implements子句和extends子句出現的順序顯現;
- interfaces表中的每一項都是對父介面的常量池的索引,該索引用CONSTANT_Class_info來描述;
- 如果介面數為0,則沒有interfaces表;
- fields_count-u2和fields(欄位列表)
- 只有在class檔案中由類或介面聲明了的欄位才在fields列表中列出,不列出從超類或父介面中繼承而來的欄位;
- fields列表可能會包含在對應的Java源檔案中沒有敘述的欄位,這是因為Java編譯器可能會在編譯時間向類或者介面添加欄位;如對一個內部類的fields列表來說,為了保持對外圍類執行個體的引用,Java編譯器會為每個外圍類執行個體添加執行個體變數;
- 第個field_info表包含以下欄位資訊:
- 欄位名字
- 欄位描述符和修飾符
- 如果該欄位被聲明為final,則還包含其常量值;
- methods_count-u2和methods(方法列表)
- methods_count表示該類或介面中所聲明的所有方法的總計數,不包括超類或都父介面中繼承來的方法;
- methods列表中包含以下資訊:
- 方法名和描述符(方法的傳回值類型和參數類型)
- 如果方法即不是抽象的,也不是本地的,則還包含方法局部變數所需的棧空間長度、為方法所捕獲的異常表、位元組碼序列以及可選的行數和局部變數表
- 如果方法能夠拋出任何已驗證異常,則methods列表就會包括一個關於這些已驗證異常的列表
- attributes_count-u2和attributes(屬性列表)
- class檔案中最後的部分是屬性,它給出了該檔案中類或介面所定義的屬性的基本資料;
- 每個attribute_info表的第一項是指向常量池中CONSTANT_Utf8_info表的索引,該表給出了屬性的名稱;
class檔案內容舉例:
- 代碼
public interface MyInterface {
void hello();
}
- 編譯後其位元組碼如:
- 常量池數"0009"表示後面緊接著有8個常量池項
- 常量池索引1表示一個CONSTANT_Class_info表(07),它引用索引為7的常量池;
- 常量池索引2表示一個CONSTANT_Class_info表(07),它引用索引為8的常量池;
- 常量池索引3表示一個CONSTANT_Utf8_info表(01),其內容為hello(方法名);
- 常量池索引4表示一個CONSTANT_Utf8_info表(01),其內容為()V(方法參數與傳回值);
- 常量池索引5表示一個CONSTANT_Utf8_info表(01),其內容為SourceFile(某屬性值);
- 常量池索引6表示一個CONSTANT_Utf8_info表(01),其內容為MyInterface.java(某屬性值);
- 常量池索引7表示一個CONSTANT_Utf8_info表(01),其內容為MyInterface,被常量池索引1引用到(當前類);
- 常量池索引8表示一個CONSTANT_Utf8_info表(01),其內容為java/lang/Object,被常量池索引2引用到(超類);
- 訪問標誌"0601"表示是public(0001)、abstract(0400),且是介面(0200);
- 當前類索引號"0001"表示指向常量池索引1,指明當前類為MyInterface;
- 超類索引號"0002"表示指向常量池索引2,指明超類為java/lang/Object;
- 實現的介面數"0000"表示沒有實現任何介面;
- 欄位數"0000"表示該介面沒有欄位;
- 方法數"0001"表示介面有一個方法;
- 剩下的位元組碼為方法列表及屬性列表;
二、特殊字元串
全限定名
常量池指向類或者介面時,給出的是全限定名,形如java/util/Hashtable;
簡單名稱
欄位名和方法名以簡單名稱形式出現在常量池入口中,如上例中的常量池索引3中的"hello";
描述符
- 指向欄位和方法的符號引用還包含描述符字串;欄位的描述符給出了欄位的類型,方法描述符給出了方法的傳回值和方法參數的數量、類型以及順序;
- 描述符使用上下文無關文法:斜體表示非終結符,等寬字型表示終結符;
- 如下所示:
- 基本類型終結符
| 終結符 |
類型 |
| B |
byte |
| C |
char |
| D |
double |
| F |
float |
| I |
int |
| J |
long |
| S |
short |
| Z |
boolean |
- 描述符舉例
| 描述符 |
說明 |
| I |
int i; |
| [Ljava/lang/Object; |
java.lang.Object[] obj; |
| ([BII)Ljava/lang/String; |
String method(byte[] b, int i, int j) |
| ZILjava/lang/String;II()Z |
boolean method(boolean b, int i, String s, int j, int k) |
本文系轉載,原文:http://diecui1202.iteye.com/blog/611476