Java 位元組碼是 Java 虛擬機器執行的一種指令格式。大多數都是一個位元組長，而有些操作需要引數，導致了有一些多位元組的操作碼。而且並不是所有可能的 256 個操作碼都被使用；其中有 51 個操作碼被保留做將來使用。除此之外，原始 Java 平臺開發商，昇陽微系統，額外保留了 3 個程式碼永久不使用。 與 Java 的關係 一個 Java 程式設計師並不需要理解所有的 Java 位元組碼。但是，就像 IBM developerWorks 週刊建議的那樣：理解位元組碼以及理解 Java 編譯器如何生成 Java 位元組碼與學習彙編知識對於 CC 程式設計師有一樣的意義。 指令 指令碼為一個位元組，有 256 個可能的程式碼值（28256），因此一個位元組的指令碼最多可能有 256 種不同的操作。其中，0x00、0xFE、0xCA、0xFF 被指定保留。例如 0xCA 作為一個 Java 偵錯程式的中斷指令而從未被語言使用。相似地，0xFE 和 0xFF 也未被語言使用。 指令可以基本分為以下幾類： 儲存指令 （例如：aload_0，istore） 算術與邏輯指令 （例如 ladd，fcmpl） 型別轉換指令 （例如：i2b，d2i） 物件建立與操作指令 （例如：new，putfield） 堆疊操作指令 （例如：swap，dup2） 控制轉移指令 （例如：ifeq，goto） 方法呼叫與返回指令 （例如：invokespecial，areturn 除此之外，還有一些更特殊的指令，作為異常丟擲或同步等作用。 大多數的指令有字首和（或）字尾來表明其運算元的型別。如下表 前 字尾 運算元型別 i 整數 l 長整數 s 短整數 b 位元組 c 字元 f 單精度浮點數 d 雙精度浮點數 z 布林值 a 引用 例如，iadd 指令將兩個整數相加；而 dadd 指令將兩個 double 浮點數相加。 const、 load、 store 等涉及儲存命令還會使用 _n 字尾，其中 load 和 store 命令中的 n 可以為 0 到 3 之間的整數；而 const 命令中的 n 由型別指定。const 指令把一個指定型別的值放入堆疊。例如 iconst_5 指令將一個整數 5 放入堆疊；而 dconst_1 將一個雙精度浮點數 1 放入堆疊。aconst_null 指令是放入一個 null 進堆疊。而對於 load store 指令中的 n，指定了變量表中的儲存位置。aload_0 指令把在變數 0 中的物件（通常是 this 物件）放入堆疊，istore_1 指令把棧頂的一個整數放入變數 1。對於更高的變數，字尾將被去除，而這條指令將需要運算元。 計算模型 Java 位元組碼的計算模型是面向堆疊結構計算機的。例如，一個 x86 處理器的彙編程式碼如下 mov eax byte ebp4 mov edx byte ebp8 add eax edx mov ecx eax 這段程式碼將兩個數值相加，並存入另一個地址。相似的反彙編位元組碼如下 0 iload_1 1 iload_2 2 iadd 3 istore_3 在這裡，需要相加的兩個運算元被放入堆疊，而相加操作就在棧中進行，其結果也被放入堆疊。儲存指令之後把棧頂的資料放入一個變數地址。在每條指令前面的數字僅僅是表示這條指令到方法開始處的偏移值。這種堆疊結構也可以推廣到面向物件模型上。例如，有一個 getName 方法如下 Method javalangString getName 0 aload_0 this 物件被存入變數 0 1 getfield 5 Field javalangString name 這個指令從棧頂取出一個物件，並從中搜索一個指定的域 並將相應的資料存入棧頂。 這個例子中，name 域對應於該類中的第五個常量。 4 areturn 返回棧頂的物件作為函式的返回值 例子 考慮如下 Java 程式碼 outer for int i 2 i 1000 i for int j 2 j i j if i j 0 continue outer Systemoutprintln i 假設上述程式碼位於一個函式中，Java 編譯器可能將程式碼翻譯成下述的 Java 位元組碼。 0 iconst_2 1 istore_1 2 iload_1 3 sipush 1000 6 if_icmpge 44 9 iconst_2 10 istore_2 11 iload_2 12 iload_1 13 if_icmpge 31 16 iload_1 17 iload_2 18 irem 19 ifne 25 22 goto 38 25 iinc 2 1 28 goto 11 31 getstatic 84 Field javalangSystemoutLjavaioPrintStream 34 iload_1 35 invokevirtual 85 Method javaioPrintStreamprintlnI V 38 iinc 1 1 41 goto 2 44 return 基於 Java 位元組碼的語言 最常用的基於 Java 位元組碼的語言就是開發出 Java 位元組碼的 Java 語言。剛開始，只存在一個由昇陽微系統開發的一個編譯器 javac。而現在 Java 位元組碼規範已經可以得到，因此，第三方公司亦開發出支援 Java 位元組碼的編譯器。例如： Jikes，編譯 Java 原始碼到 Java 位元組碼（由 IBM 開發，用 C 實現） Espresso，編譯 Java 原始碼到 Java 位元組碼（僅支援 Java 10） GCJ，GNU Compiler for Java，編譯 Java 程式碼到 Java 位元組碼；亦可以編譯到機器程式碼。作為 GNU Compiler Collection GCC 的一部分提供。 有一些專案提供 Java 彙編器以便於直接用 Java 位元組碼進行開發。主要的 Java 彙編器如下： Jasmin，讀取 Java 類的文字描述；用一種簡單的使用 Java 虛擬機器指令的類彙編語法，輸出 Java 類檔案 Jamaica， 一種為 Java 虛擬機器編寫的宏組合語言。其中，類與介面由 Java 語法定義，而其中的方法卻由 Java 位元組碼定義。 還有其他的一些編譯器，對於其他語言生成 Java 位元組碼，使其可以執行在 Java 虛擬機器之上。 Adobe ColdFusion JRuby 和 Jython， 兩種基於 Ruby 和 Python 的指令碼語言 Groovy 一種基於 Java 的指令碼語言 Scala 一種型別安全的通用程式語言，支援面向物件程式設計和函數語言程式設計 JGNAT 和 AppleMagic 編譯 Ada 語言到 Java 位元組碼 Clojure 一種函式式的通用程式語言，提供優秀的併發性。是一種 LISP 方言 MIDletPascal JavaFX Script 由昇陽微系統公司開發的一種指令碼語言，運行於 Java 虛擬機器之上 執行 當前已經有很多種 Java 虛擬機器產品，包括了自由軟體和商業軟體。如果在 Java 虛擬機器之中執行 Java 位元組碼並不理想，則可以使用一些工具例如 GNU Compiler for Java 將 Java 程式碼或 Java 位元組碼編譯成機器碼並由硬體直接執行。 而有一些處理器可以直接執行 Java 位元組碼，這種處理器名為 Java 處理器。 對動態語言的支援 Java 虛擬機器對動態型別語言提供了一定的支援。但絕大多數的 Java 虛擬機器指令集是基於靜態型別語言的。在靜態型別機制下，方法呼叫中的型別分析都是在編譯時執行的，而且缺乏一種機制在執行時確定一個型別已經確定相應的方法。 JSR292 中，在 Java 虛擬機器層次增加了一種支援動態型別的指令 invokedynamic，以支援在動態型別檢測中的方法呼叫。 則是一種支援這種動態型別呼叫的虛擬機器。 而所有支援 JSE 7 的 Java 虛擬機器都應支援 invokedynamic 操作碼。 參考文獻 位元組碼 Category 組合語言 Category 位元組碼