小師妹學JVM之:java的字節碼byte code簡介

目錄

  • 簡介
  • Byte Code的作用
  • 查看Byte Code字節碼
  • java Byte Code是怎麼工作的
  • 總結

簡介

Byte Code也叫做字節碼,是連接java源代碼和JVM的橋樑,源代碼編譯成為字節碼,而字節碼又被加載進JVM中運行。字節碼怎麼生成,怎麼查看字節碼,隱藏在Byte Code背後的秘密是什麼呢?快跟小師妹一起來看看吧。

Byte Code的作用

小師妹:F師兄,為什麼Java需要字節碼呢?直接編譯成為機器碼不是更快嗎?

小師妹,Java的設計初衷是一次編寫,到處運行。為了兼容各個平台的運行環境,java特別為各種平台設計了JVM。

我們可以把JVM看做是一種抽象,對外提供了統一的接口。這樣我們只需要編寫符合JVM規範的代碼,即可在JVM中運行。

回想下之前我們提到過的java的執行過程:

  1. 編寫java代碼文件比如Example.java
  2. 使用java編譯器javac將源文件編譯成為Example.class文件
  3. JVM加載生成的字節碼文件,將其轉換成為機器可以識別的native machine code執行

小師妹:F師兄,我有一個大膽的想法,JVM的作用是將字節碼解釋或者編譯成為機器碼。然後在相應的運行環境中執行。那麼有沒有可能,不需要JVM,不需要機器碼,而是直接在對應的平台上執行字節碼呢?

愛因斯坦說過沒有想像力的靈魂,就像沒有望遠鏡的天文台。小師妹你這個想法很好,這種實現有個專業的說法叫做:Java processor。

Java processor就是用硬件來實現的JVM。因此字節碼可以直接在Java processor中運行。

其中比較出名的是Jazelle DBX,這是一個主要支持J2ME環境的硬件架構。為了提升java在手機端的執行速度。

但是這樣做其實也是有缺點的,後面我們會講到,java字節碼中的指令非常非常多。所以如果用硬件來實現的話,就會非常非常複雜。

一般來說Java processor不會實現全部的字節碼中的功能,只會提供部分的實現。

查看Byte Code字節碼

小師妹:F師兄,那使用javac編譯過後的class文件跟字節碼有什麼關係呢?

class文件中大部分都是byte code,其他的部分是一些meta data元數據信息。這些組合在一起就是class文件了。

小師妹:F師兄,你說class文件是byte code,為什麼我在IDE中打開的時候,直接显示的是反編譯出來的源文件呢?

小師妹,這是IDE的一個便利功能。因為大多數情況下,沒有人想去看class文件的Byte code的,大家都是想去看看這個class文件的源文件是什麼樣的。

我們舉個最簡單的例子:

這個類中,我們定義了一個很簡單的testByteCode方法,裏面定義了兩個變量,然後返回他們兩個的和。

現在有兩種方法來查看這個類的Byte Code:

第一種方法是用javap命令:

javap -c ByteCodeUsage.class

生成的結果如上所示。

第二種方法就是在IDEA中,選中class文件,然後在view中選中show Bytecode:

我們看下輸出結果:

兩個的結果在显示上面可能有細微的差異,但是並不影響我們後面對其的解析。

java Byte Code是怎麼工作的

小師妹:F師兄,能講解一下這些byte code到底是怎麼工作的嗎?

首先我們要介紹一下JVM的實現是基於棧的結構的。為什麼要基於棧的結構呢?那是因為棧是最適合用來實現function互相調用的。

我們再回顧一下上面的testByteCode的字節碼。裏面有很多iconst,istore的東西,這些東西被稱作Opcode,也就是一些基於棧的操作指令。

上面講了java bytecode的操作指令其實有很多個。下面我們列出這些指令的部分介紹:

實在是太多了,這裏就不把所有的列出來了。

我們看到的指令名字其實是一個助記詞,真實的Opcode是一個佔用兩個字節的数字。

下面我們來詳細解釋一下testByteCode方法:

public int testByteCode();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: ireturn

第一步,iconst_1將int 1加載到stack中。

第二步,istore_1將入棧的int 1出棧,並存儲到變量1中。

第三步,iconst_2將int 2入棧。

第四步,istore_2將入棧的int 2出棧,並存儲到變量2中。

第五步,iload_1將變量1中的值入棧。

第六步,iload_2將變量2中的值入棧。

第七步,iadd將棧中的兩個變量出棧,並相加。然後將結果入棧。

第八步,ireturn將棧中的結果出棧。

這幾步實際上完美的還原了我們在testByteCode方法中定義的功能。

當然我們只介紹了最賤的byte code命令,通過這些簡單的命令可以組合成為更加複雜的java命令。

總結

本文介紹了java byte code的作用和具體的指令,並分析了一個簡單的例子來做說明。希望大家能夠掌握。

本文的例子https://github.com/ddean2009/learn-java-base-9-to-20

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/jvm-byte-code/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等着您!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!