Java虛擬機(jī)字節(jié)碼指令簡(jiǎn)介

目錄:

1、字節(jié)碼與數(shù)據(jù)類型
2、加載和存儲(chǔ)指令
3感挥、運(yùn)算指令
4缩搅、類型轉(zhuǎn)換指令
5、對(duì)象創(chuàng)建與訪問指令
6链快、操作數(shù)棧管理指令
7誉己、控制轉(zhuǎn)義指令
8、方法調(diào)用和返回指令
9域蜗、異常處理指令
10巨双、同步指令

Java 虛擬機(jī)的指令由一個(gè)字節(jié)長(zhǎng)度的、代表著某種特定操作含義的數(shù)字(稱為操作碼)以及跟隨其后的零至多個(gè)代表此操作所需參數(shù)(操作數(shù))而構(gòu)成霉祸。由于 Java 虛擬機(jī)采用面向操作數(shù)棧而不是寄存器的架構(gòu)筑累,所以大多數(shù)的指令都不包含操作數(shù),只有一個(gè)操作碼丝蹭。

1慢宗、字節(jié)碼與數(shù)據(jù)類型

在 Java 虛擬機(jī)的指令集中,大多數(shù)的指令都包含了其操作所對(duì)應(yīng)的數(shù)據(jù)類型信息奔穿。例如镜沽,iload 指令用于從局部變量表中加載 int 型的數(shù)據(jù)到操作數(shù)棧中,而 fload 指令加載的則是 float 類型的數(shù)據(jù)贱田。這兩條指令的操作在虛擬機(jī)內(nèi)部可能會(huì)是由同一段代碼來實(shí)現(xiàn)缅茉,但在 Class 文件中它們必須擁有各自獨(dú)立的操作碼。

對(duì)于大部分與數(shù)據(jù)類型相關(guān)的字節(jié)碼指令男摧,它們的操作碼助記符中都有特殊的字符表明專門為哪種數(shù)據(jù)類型服務(wù):i 代表對(duì) int 類型的數(shù)據(jù)操作蔬墩,l 代表 long,s 代表 short耗拓,b 代表 byte拇颅,c 代表 char,f 代表 float乔询,d 代表 double樟插,a 代表 reference。也有一些指令的助記符中沒有明確的指明操作類型的字母竿刁,如 arraylength 指令岸夯,它沒有代表數(shù)據(jù)類型的特殊字符,但操作數(shù)永遠(yuǎn)只能是一個(gè)數(shù)字類型的對(duì)象们妥。還有另外一些指令猜扮,如無條件跳轉(zhuǎn)指令 goto 則是與數(shù)據(jù)類型無關(guān)的。

2监婶、加載和存儲(chǔ)指令

加載和存儲(chǔ)指令用于將數(shù)據(jù)在棧幀中的局部變量表和操作數(shù)棧之間來回傳輸旅赢,這類指令包括如下內(nèi)容:

  • 將一個(gè)局部變量加載到操作棧:iload齿桃、iload_<n>、lload煮盼、lload_<n>短纵、fload、fload_<n>僵控、dload香到、dload_<n>、aload报破、aload_<n>悠就。
  • 將一個(gè)數(shù)值從操作數(shù)棧存儲(chǔ)到局部變量表中:istore、istore_<n>充易、lstore梗脾、lstore_<n>、fstore盹靴、fstore_<n>炸茧、dstore、dstore_<n>稿静、astore梭冠、astore_<n>。
  • 將一個(gè)常量加載到操作數(shù)棧:bipush改备、sipush控漠、ldc、ldc_w绍妨、ldc2_w、aconst_null柬脸、iconst_m1他去、iconst_<i>、lconst_<l>倒堕、fconst_<f>灾测、dconst_<d>。
  • 擴(kuò)充局部變量表的訪問索引的指令:wide垦巴。

3媳搪、運(yùn)算指令

運(yùn)算或算術(shù)指令用于對(duì)兩個(gè)操作數(shù)棧上的值進(jìn)行某種特定運(yùn)算,并把結(jié)構(gòu)重新存入到操作棧頂骤宣。大體上算術(shù)指令可以分為兩種:對(duì)整形數(shù)據(jù)進(jìn)行運(yùn)算的指令與對(duì)浮點(diǎn)型數(shù)據(jù)進(jìn)行運(yùn)算的指令秦爆,無論是哪種算術(shù)指令,都使用 Java 虛擬機(jī)的操作類型憔披,由于沒有直接支持 byte等限、short爸吮、char 和 boolean 類型算術(shù)指令,對(duì)于這些數(shù)據(jù)的運(yùn)算望门,應(yīng)使用操作 int 類型的指令代替形娇。整數(shù)與浮點(diǎn)數(shù)的算術(shù)指令在溢出和被零除的時(shí)候也有各自不同的行為表現(xiàn),所有的算術(shù)指令如下筹误。

  • 加法指令:iadd桐早、ladd、fadd厨剪、dadd哄酝。
  • 減法指令:isub、lsub丽惶、fsub炫七、dsub。
  • 乘法指令:imul钾唬、lmul万哪、fmul、dmul抡秆。
  • 除法指令:idiv奕巍、ldiv、fdiv儒士、ddiv的止。
  • 求余指令:irem、lrem着撩、frem诅福、drem。
  • 取反指令:ineg拖叙、lneg氓润、fneg、dneg薯鳍。
  • 位移指令:ishl咖气、ishr、iushr挖滤、lshl崩溪、lshr、lushr斩松。
  • 按位或指令:ior伶唯、lor。
  • 按位與指令:iand惧盹、land抵怎。
  • 按位異或指令:ixor奋救、lxor。
  • 局部變量自增指令:iinc反惕。
  • 比較指令:dcmpg尝艘、dcmpl、fcmpg姿染、fcmpl背亥、lcmp。

4悬赏、類型轉(zhuǎn)換指令

Java 虛擬機(jī)直接支持以下數(shù)值類型的寬化類型轉(zhuǎn)換(自動(dòng)轉(zhuǎn)換):

  • int 類型到 long狡汉、float 或者 double 類型。
  • long 類型到 float闽颇、double 類型盾戴。
  • float 類型到 double 類型。

相對(duì)的兵多,處理窄化轉(zhuǎn)換時(shí)尖啡,必須顯式的使用轉(zhuǎn)換指令來完成(即強(qiáng)轉(zhuǎn))。這些轉(zhuǎn)換指令包括:i2b剩膘、i2c衅斩、i2s、l2i怠褐、f2i畏梆、f2l、d2i奈懒、d2l 和 d2奠涌。

5、對(duì)象創(chuàng)建與訪問指令

雖然類實(shí)例和數(shù)組都是對(duì)象磷杏,但 Java 虛擬機(jī)對(duì)類實(shí)例和數(shù)組的創(chuàng)建與操作使用了不同的字節(jié)碼指令溜畅。

  • 創(chuàng)建類實(shí)例的指令:new。
  • 創(chuàng)建數(shù)組的指令:newarray茴丰、anewarray达皿、multianewarray天吓。
  • 訪問類字段和實(shí)例字段的指令:getfield贿肩、putfield、getstatic龄寞、putstatic汰规。
  • 把一個(gè)數(shù)組元素加載到操作數(shù)棧的指令:baload、caload物邑、saload溜哮、iaload滔金、laload、faload茂嗓、daload餐茵、aaload。
  • 將一個(gè)操作數(shù)棧的值存儲(chǔ)到數(shù)組元素中的指令:bastore述吸、castore忿族、sastore、iastore蝌矛、fastore道批、dastore、aastore入撒。
  • 取數(shù)組長(zhǎng)度的指令:arraylength隆豹。
  • 檢查類實(shí)例類型的指令:instanceof、checkcast茅逮。

6璃赡、操作數(shù)棧管理指令

如同操作一個(gè)普通數(shù)據(jù)結(jié)構(gòu)中的堆棧那樣,Java 虛擬機(jī)提供了一些用于直接操作數(shù)棧的指令氮唯,包括:

  • 將操作數(shù)棧的棧頂一個(gè)或兩個(gè)元素出棧:pop鉴吹、pop2。
  • 復(fù)制棧頂一個(gè)或兩個(gè)數(shù)值并將復(fù)制值或雙份的復(fù)制值重新壓入棧頂:dup惩琉、dup2豆励、dup_x1、dup2_x1瞒渠、dup_x2良蒸、dup2_x2。
  • 將棧最頂端的兩個(gè)數(shù)值互換:swap伍玖。

7嫩痰、控制轉(zhuǎn)義指令

控制轉(zhuǎn)義指令可以讓 Java 虛擬機(jī)有條件或無條件的從指定的位置指令而不是控制轉(zhuǎn)義指令的下一條指令繼續(xù)執(zhí)行程序。

  • 條件分支:ifeq窍箍、iflt串纺、ifle、ifne椰棘、ifgt纺棺、ifnull、ifnonnull邪狞、if_icmpeq祷蝌、if_icmpne、if_icmplt帆卓、if_icmpgt巨朦、if_icmple米丘、if_icmpge、if_acmpeg 和 if_acmpne糊啡。
  • 復(fù)合條件分支:tableswitch拄查、lookupswitch。
  • 無條件分支:goto棚蓄、goto_w靶累、jsr、jsr_w癣疟、ret挣柬。

8、方法調(diào)用和返回指令

這里列出一下 5 條用于方法調(diào)用的指令睛挚。

  • invokevirtual 指令用于調(diào)用對(duì)象的實(shí)例方法邪蛔,根據(jù)對(duì)象的實(shí)例類型進(jìn)行分派。
  • invokeinterfce 指令用于調(diào)用接口方法扎狱,它會(huì)在運(yùn)行時(shí)搜索一個(gè)實(shí)現(xiàn)類這個(gè)接口方法的對(duì)象侧到,找出適合的方法進(jìn)行調(diào)用。
  • invokespecial 指令用于調(diào)用一些需要特需處理的實(shí)例方法淤击,包括實(shí)例初始化方法匠抗、私有方法和父類方法。
  • invokestatic 指令用于調(diào)用類方法污抬。
  • invokedynamic 指令用于在運(yùn)行時(shí)動(dòng)態(tài)解析出調(diào)用點(diǎn)限定符所引用的方法汞贸,并執(zhí)行該方法。

方法調(diào)用指令與數(shù)據(jù)類型無關(guān)印机,而方法返回指令是根據(jù)返回值的類型區(qū)分的矢腻,包括 ireturn(當(dāng)返回值是 boolean、byte射赛、char多柑、short 和 int 類型時(shí)使用)、lreturn楣责、freturn翔烁、dreturn 和 areturn穿扳。另外還有一條 return 指令供聲明為 void 的方法赊淑、實(shí)例初始化方法以及類和接口的類初始化方法使用蜒蕾。

9、異常處理指令

在 Java 程序顯式的拋出異常的操作(throw 語(yǔ)句)都由 athrow 指令來實(shí)現(xiàn)蛔屹。而在 Java 虛擬機(jī)中削樊,處理異常(catch 語(yǔ)句)不是有字節(jié)碼指令來實(shí)現(xiàn)的豁生,而是采用異常表來完成的兔毒。

10漫贞、同步指令

Java 虛擬機(jī)可以支持方法級(jí)的同步(即同步方法)和方法內(nèi)部一段指令序列的同步(即同步代碼塊),這兩種同步結(jié)構(gòu)都是使用管程(Monitor)來支持的育叁。

  • 方法級(jí)的同步是隱式的迅脐,即無須通過字節(jié)碼指令來控制,它實(shí)現(xiàn)再方法調(diào)用和返回操作之中豪嗽。虛擬機(jī)可以從方法常量池的方法表結(jié)構(gòu)中的 ACC_SYNCHRONIZED 訪問標(biāo)志得知一個(gè)方法是否聲明為同步方法谴蔑。當(dāng)方法調(diào)用時(shí),調(diào)用指令將會(huì)檢查方法的 ACC_SYNCHRONIZED 訪問標(biāo)志是否被設(shè)置龟梦,如果設(shè)置了隐锭,執(zhí)行線程就要求先成功持有管程(Monitor),然后才能執(zhí)行方法计贰,最后當(dāng)方法完成時(shí)釋放管城钦睡。在方法執(zhí)行期間,執(zhí)行線程持有了管程躁倒,其他任何線程都無法在獲取到同一個(gè)管程荞怒。如果一個(gè)同步方法執(zhí)行期間拋出了一次,并且在方法內(nèi)部無法處理此異常秧秉,那么這個(gè)同步方法所持有的管程將在異常拋出到同步方法之外時(shí)自動(dòng)釋放褐桌。
  • 同步一段指令集序列通常是由 Java 語(yǔ)言中的 synchronized 語(yǔ)句塊來表示的,Java 虛擬機(jī)的指令集中有 monitorenter 和 monitorexit 兩條指令來支持 synchronized 關(guān)鍵字的語(yǔ)義象迎,正確實(shí)現(xiàn) synchronized 關(guān)鍵字需要 Javac 編譯器與 Java 虛擬機(jī)兩者共同協(xié)作支持荧嵌。

最后,Java 代碼字節(jié)碼指令可以通過 javap 命令查看砾淌,通過了解 Java 虛擬機(jī)字節(jié)碼指令的知識(shí)可以讓我們清楚的知道一個(gè)方法是怎樣執(zhí)行的完丽。舉個(gè)栗子:

public class ByteCodeTest {
    public int add(int a, int b) {
        return a + b;
    }
}

如果我們想要知道 add() 方法執(zhí)行的字節(jié)碼,可以先通過 javac ByteCodeTest.java 將 java 類編譯成 class 文件拇舀,然后通過 javap -verbose ByteCodeTest 命令就可以得到如下結(jié)果:

  public com.np.vm.ByteCodeTest();
    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 3: 0

  public int add(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: iload_1
         1: iload_2
         2: iadd
         3: ireturn
      LineNumberTable:
        line 5: 0

這樣我們就能看到 add() 方法的字節(jié)碼執(zhí)行結(jié)果逻族,了解了字節(jié)碼指令,就能很輕松的看懂各種方法執(zhí)行的字節(jié)碼指令骄崩,如果想要知道每個(gè)方法的字節(jié)碼執(zhí)行過程可以看下面這篇文章聘鳞。
「虛擬機(jī)的方法調(diào)用和字節(jié)碼執(zhí)行」

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市要拂,隨后出現(xiàn)的幾起案子抠璃,更是在濱河造成了極大的恐慌,老刑警劉巖脱惰,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搏嗡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)采盒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門旧乞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人磅氨,你說我怎么就攤上這事尺栖。” “怎么了烦租?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵延赌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我叉橱,道長(zhǎng)挫以,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任窃祝,我火速辦了婚禮屡贺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锌杀。我一直安慰自己甩栈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布糕再。 她就那樣靜靜地躺著量没,像睡著了一般。 火紅的嫁衣襯著肌膚如雪突想。 梳的紋絲不亂的頭發(fā)上殴蹄,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音猾担,去河邊找鬼袭灯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绑嘹,可吹牛的內(nèi)容都是我干的稽荧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼工腋,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼姨丈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起擅腰,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤蟋恬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后趁冈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歼争,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拜马,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沐绒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俩莽。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖洒沦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情价淌,我是刑警寧澤申眼,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蝉衣,受9級(jí)特大地震影響括尸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜病毡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一濒翻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啦膜,春花似錦有送、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至八拱,卻和暖如春阵赠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肌稻。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工清蚀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爹谭。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓枷邪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親诺凡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子齿风,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容