代碼編譯的結果從本地機器碼轉變?yōu)樽止?jié)碼拼苍,是存儲格式發(fā)展的一小步,卻是編程語言發(fā)展的一大步调缨。
一疮鲫、Class類文件的結構
??Class文件是一組以8位字節(jié)為基礎單位的二進制流吆你,各個數(shù)據(jù)項目嚴格按照順序緊湊地排列在Class文件之中,中間沒有添加任何分隔符俊犯,這使得整個Class文件中存儲的內容幾乎全部是程序運行的必要數(shù)據(jù)妇多,當遇到需要占用8位字節(jié)以上空間的數(shù)據(jù)項時,則會按照高位在前的方式分割成若干個8位字節(jié)進行存儲燕侠。
??Class文件格式只有兩種數(shù)據(jù)類型:無符號數(shù)和表者祖。 無符號數(shù)屬于基本的數(shù)據(jù)類型,以u1绢彤、u2咸包、u4、u8來分別代表1個字節(jié)杖虾、2個字節(jié)、4個字節(jié)和8個字節(jié)的無符號數(shù)媒熊。表是由多個無符號數(shù)或者其他表作為數(shù)據(jù)項構成的復合數(shù)據(jù)類型奇适,所有表都習慣性的以“_info”結尾。
Class文件格式:
a)magic
類型:u4芦鳍,數(shù)量1
簡介:每個Class文件的頭4個字節(jié)稱為魔數(shù)嚷往,它的唯一作用是確定這個文件是否為一個能被虛擬機接受的Class文件。
b)minor_version
類型:u2柠衅,數(shù)量1
c)major_version
類型:u2皮仁,數(shù)量1
簡介:緊接著魔數(shù)的4個字節(jié)存儲的是Class文件的版本號
d)constant_pool_count
類型:u2,數(shù)量1
簡介:緊接著版本號的是常量池入口菲宴,這個字段是常量池容量計數(shù)值贷祈。
e)constant_pool
類型:cp_info,數(shù)量constant_pool_count-1
簡介:常量池中主要存放兩大類常量:字面量和符號引用喝峦。
字面量比較接近Java語言層面的常量概念势誊,如溫恩字符串、聲明為final的常量值等谣蠢;而符號引用則屬于編譯原理方面的概念粟耻,包括下面三類常量:
類和接口的全限定名、字段的名稱和描述符眉踱、方法的名稱和描述符挤忙。
關于編譯
??Java編譯時并不像C和C++那樣有“連接”步驟,而是在虛擬機加載Class文件的時候才進行動態(tài)連接谈喳。就是說册烈,在Class文件中不會保存各個方法、字段的最終內存布局信息婿禽。
f)access_flag
類型:u2茄厘,數(shù)量1
簡介:這個訪問標志用于識別一些類或者接口層次的訪問信息矮冬,比如是類還是接口,是否為public類型次哈。
g)類索引胎署、父類索引與接口索引集合
類型:this_class u2 數(shù)量1,super_class u2 數(shù)量1窑滞, interfaces_count u2 數(shù)量1琼牧,interfaces u2 數(shù)量interface_count。
簡介:Class文件中由這三項數(shù)據(jù)來確定這個類的繼承關系哀卫。
h)字段表集合
類型:fields_count u2 數(shù)量1巨坊,fields field_info 數(shù)量fields_count
簡介:字段表(field_info)用于描述接口或者類中聲明的變量。字段(field)包括類級變量以及實例級變量此改,但不包括在方法內部聲明的局部變量趾撵。
i)方法表集合
類型:methods_count u2 數(shù)量1,methods method_info 數(shù)量methods_count
簡介:方法表結構包括范文標志共啃、名稱索引占调、描述符索引、屬性表集合移剪。
j)屬性表集合
類型:attributes_count u2 數(shù)量1究珊,attributes attribute_count 數(shù)量attributes_count
簡介:在Class文件、字段表纵苛、方法表都可以攜帶自己的屬性表集合剿涮,以描述某些場景專有的信息。
二攻人、字節(jié)碼指令簡介
1.字節(jié)碼與數(shù)據(jù)類型
??在Java虛擬機的指令集中取试,大多數(shù)的指令都包含了其操作所對應的數(shù)據(jù)類型信息。如iload指令用于從局部變量表中加載int型的數(shù)據(jù)到操作數(shù)棧中怀吻,d代表double想括,s代表short、a代表reference烙博。也有一些指令的助記符中沒有明確知名操作類型的字母瑟蜈,如arraylength指令,它沒有代表數(shù)據(jù)類型的特殊字符渣窜,但操作數(shù)永遠只能是一個數(shù)組類型的對象铺根。
2.加載與存儲指令
??用于將數(shù)據(jù)在棧幀中的局部變量表和操作數(shù)棧之間來回傳輸。
a)將一個局部變量加載到操作數(shù)棧:iload乔宿、lload位迂、fload、dload、aload
b)將一個數(shù)值從操作數(shù)棧存儲到局部變量表:istore掂林、lstore臣缀、fstore、dstore泻帮、astore
c)將一個常量加載到操作數(shù)棧:bipush精置、sipush、ldc锣杂、aconst脂倦、iconst、fconst
d)擴充局部變量表的訪問索引的指令:wide
3.運算指令
??用于對兩個操作數(shù)棧上的值進行某種特定運算元莫,并把結果存入到棧頂赖阻。
加法指令:iadd、ladd踱蠢、fadd火欧、dadd
減法指令:isub、lsub茎截、fsub苇侵、dsub
乘法指令:imul、lmul稼虎、fmul、dmul
除法指令:idiv招刨、ldiv霎俩、fdiv、ddiv
求余指令:irem沉眶、lrem打却、frem、drem
省略寫法:取反:neg谎倔;位移:shr柳击;位或:or;位與:and片习;位異或:xor捌肴;局部變量自增:inc
4.類型轉換指令
??寬化類型轉換:即小范圍類型向大范圍類型的安全轉換,如int轉float藕咏、long等状知,直接支持不需指令。
??窄化類型轉換:必須顯示指定轉換指令孽查,如i2b饥悴,i2s,f2i,d2f等西设。
5.對象創(chuàng)建與訪問指令
創(chuàng)建類實例的指令:new
創(chuàng)建數(shù)組的指令:newarray瓣铣、anewearray、multianewarray
訪問類字段和實例字段的指令:getfield贷揽、putfield棠笑、getstatic、putstatic
把一個數(shù)組元素加載到操作數(shù)棧的指令:baload擒滑、caload腐晾、saload、iaload丐一、faload藻糖、daload、aaload
將一個操作數(shù)棧的值存儲到數(shù)組元素中的指令:bastore库车、castore巨柒、sastore、iastore柠衍、fastore洋满、dastore、aastore
取數(shù)組長度的指令:arraylength
檢查類實例類型的指令:instantceof珍坊、checkcast
6.操作數(shù)棧管理指令
將操作數(shù)棧的棧頂一個或兩個元素出棧:pop牺勾、pop2
復制棧頂一個或兩個數(shù)值并將復制值或雙份的復制值重新壓入棧頂:dup、dup2阵漏、dup_x1驻民、dup2_x1、dup_x2履怯、dup2_x2
將棧最頂端的兩個數(shù)值互換:swap
7.控制轉移指令
條件分支(如ifeq回还、ifle)、符合條件分支叹洲、無條件分支(如goto柠硕、ret)
8.方法調用和返回指令
invokevirtual:調用對象的實例方法
invokeinterface:調用接口方法,它會在運行時搜索一個實現(xiàn)了這個接口方法的對象运提,找出合適的方法進行調用
invokespecial:調用一些需要特殊處理的實例方法蝗柔,如實例初始化方法、私有方法和父類方法
invokestatic:調用類方法
invokedynamic:用于在運行時動態(tài)解析出調用點限定符所引用的方法民泵,并執(zhí)行該方法
8.異常處理指令
Java中顯式拋出異常的操作都由athrow指令來完成
9.同步指令
Java虛擬機可支持方法級的同步和方法內部一段指令序列的同步诫咱,這兩種同步結構都是使用管程(Monitor)來支持的。方法級的同步是隱式的洪灯。同步一段指令集序列通常由Java語言中的synchronized語句塊來表示坎缭。