Java編譯過程是將Java文件轉換為Claaa文件,從而實現了跨平台的功能, 本文詳細講述Class文件結構。
計算機只能識別0和1,所以大家編寫的程序都需要經過編譯器,轉換為由0和1組成的二進制本地機器碼(Native Code)。隨著虛擬機的不斷發展,很多程序語言開始選擇與操作系統和機器指令集無關的格式作為編譯後的存儲格式(Class文件),從而實現”Write Once, Run Anywhere”。 Java設計之初,考慮後期能讓Java虛擬機運行其他語言,目前有越來越多的其他語言都可以直接需要在Java虛擬機,虛擬機只能識別Class文件,至於是由何種語言編譯而來的,虛擬機並不關心,如下圖:
可以看出不管是由Java語言,還是JRuby等其他語言,只能能生成.class字節碼文件,就都可以運行在Java虛擬機上。故發布規范文檔時,Java規范拆分為Java語言規范和Java虛擬機規范。
Java語法中定義各種變量、關鍵字、運算符的語義最終由多個字節碼命令組合而成。因此字節碼命令所能提供的語義描述能力必然要比Java語言本身更加強大。
Class文件是一組以8位字節為單位的二進制流,中間沒有任何分隔符,非常緊湊。 當需要占用8位以上的數據時,會按照Big-endian順序,高位在前,低位在後的方式來分割成多個8位字節來存儲。
Java虛擬機規范規定:Class文件格式采用偽結構來存儲數據,偽結構中只有無符號數和表這兩種數據類型。
下面介紹幾個概述:
是指把類全名中的“.”號,用“/”號替換,並且在最後加入一個“;”分號後生成的名稱。比如java.lang.Object
對應的全限定名為java/lang/Object;
。
這個比較好理解,就是直接的方法名或者字段。比如toString()
方法,不需要包名作為前綴了。
用於描述字段的數據類型。
規則如下:
例如:
用來描述方法的參數列表(數量、類型以及順序)和返回值。
格式:(參數描述符列表)返回值描述符。 例如:Object m(int i, double d, Thread t) {..}
==> IDLjava/lang/Thread;)Ljava/lang/Object;
一個Class類文件是由一個ClassFile結構組成:
ClassFile {
u4 magic; //魔數,固定值0xCAFEBABE
u2 minor_version; //次版本號
u2 major_version; //主版本號
u2 constant_pool_count; //常量的個數
cp_info constant_pool[constant_pool_count-1]; //具體的常量池內容
u2 access_flags; //訪問標識
u2 this_class; //當前類索引
u2 super_class; //父類索引
u2 interfaces_count; //接口的個數
u2 interfaces[interfaces_count]; //具體的接口內容
u2 fields_count; //字段的個數
field_info fields[fields_count]; //具體的字段內容
u2 methods_count; //方法的個數
method_info methods[methods_count]; //具體的方法內容
u2 attributes_count; //屬性的個數
attribute_info attributes[attributes_count]; //具體的屬性內容
}
一個Class文件的大小:26 + cp_info[] + u2[] + field_info[] + method_info[] + attribute_info[]
接下來,將具體來介紹ClassFile文件的各個組成部分。
每個Class文件頭4個字節稱為魔數(Magic Number),作用是用於確定這個Class文件是否能被虛擬機所接受,魔數固定值0xCAFEBABE。這是身份識別,比如jpeg等圖片文件頭也會有魔數。
緊跟魔數,也占用4個字節。從第5字節到第8字節存儲的分別是 次版本號,主版本號。
常量池是Class文件空間最大的數據項之一,長度不固定。
a. 常量池長度 用u2類型代表常量池容量計數值,u2緊跟版本號。u2的大小等於常量池的常量個數+1。對於u2=0的特殊情況,代表沒有使用常量池。
b. 常量池內容,格式如下:
cp_info {
u1 tag;
u1 info[];
}
包括兩個類常量,字面量和符號引用:
常量池中每一項常量都是一個表結構,每個表的開始第一位是u1類型的標志位tag, 代表當前這個常量的類型。在JDK 1.7.中共有14種不同的表結構的類型,如下:
Class文件都是二進制格式,可通過Jdk/bin/javap.exe
工具,分析Class文件字節碼。關於javap用法,可通過javap --help
來查看。