簡(jiǎn)介
Byte Code也叫做字節(jié)碼,是連接java源代碼和JVM的橋梁琼娘,源代碼編譯成為字節(jié)碼,而字節(jié)碼又被加載進(jìn)JVM中運(yùn)行附鸽。字節(jié)碼怎么生成,怎么查看字節(jié)碼坷备,隱藏在Byte Code背后的秘密是什么呢?快跟小師妹一起來(lái)看看吧省撑。
Byte Code的作用
小師妹:F師兄赌蔑,為什么Java需要字節(jié)碼呢?直接編譯成為機(jī)器碼不是更快嗎竟秫?
小師妹娃惯,Java的設(shè)計(jì)初衷是一次編寫,到處運(yùn)行肥败。為了兼容各個(gè)平臺(tái)的運(yùn)行環(huán)境趾浅,java特別為各種平臺(tái)設(shè)計(jì)了JVM愕提。
我們可以把JVM看做是一種抽象,對(duì)外提供了統(tǒng)一的接口皿哨。這樣我們只需要編寫符合JVM規(guī)范的代碼揪荣,即可在JVM中運(yùn)行。
回想下之前我們提到過(guò)的java的執(zhí)行過(guò)程:
- 編寫java代碼文件比如Example.java
- 使用java編譯器javac將源文件編譯成為Example.class文件
- JVM加載生成的字節(jié)碼文件往史,將其轉(zhuǎn)換成為機(jī)器可以識(shí)別的native machine code執(zhí)行
小師妹:F師兄仗颈,我有一個(gè)大膽的想法,JVM的作用是將字節(jié)碼解釋或者編譯成為機(jī)器碼椎例。然后在相應(yīng)的運(yùn)行環(huán)境中執(zhí)行挨决。那么有沒(méi)有可能,不需要JVM订歪,不需要機(jī)器碼脖祈,而是直接在對(duì)應(yīng)的平臺(tái)上執(zhí)行字節(jié)碼呢?
愛(ài)因斯坦說(shuō)過(guò)沒(méi)有想像力的靈魂刷晋,就像沒(méi)有望遠(yuǎn)鏡的天文臺(tái)盖高。小師妹你這個(gè)想法很好,這種實(shí)現(xiàn)有個(gè)專業(yè)的說(shuō)法叫做:Java processor眼虱。
Java processor就是用硬件來(lái)實(shí)現(xiàn)的JVM喻奥。因此字節(jié)碼可以直接在Java processor中運(yùn)行。
其中比較出名的是Jazelle DBX捏悬,這是一個(gè)主要支持J2ME環(huán)境的硬件架構(gòu)撞蚕。為了提升java在手機(jī)端的執(zhí)行速度。
但是這樣做其實(shí)也是有缺點(diǎn)的过牙,后面我們會(huì)講到甥厦,java字節(jié)碼中的指令非常非常多。所以如果用硬件來(lái)實(shí)現(xiàn)的話寇钉,就會(huì)非常非常復(fù)雜刀疙。
一般來(lái)說(shuō)Java processor不會(huì)實(shí)現(xiàn)全部的字節(jié)碼中的功能,只會(huì)提供部分的實(shí)現(xiàn)扫倡。
查看Byte Code字節(jié)碼
小師妹:F師兄谦秧,那使用javac編譯過(guò)后的class文件跟字節(jié)碼有什么關(guān)系呢?
class文件中大部分都是byte code镊辕,其他的部分是一些meta data元數(shù)據(jù)信息油够。這些組合在一起就是class文件了。
小師妹:F師兄征懈,你說(shuō)class文件是byte code石咬,為什么我在IDE中打開的時(shí)候,直接顯示的是反編譯出來(lái)的源文件呢鬼悠?
小師妹,這是IDE的一個(gè)便利功能焕窝。因?yàn)榇蠖鄶?shù)情況下,沒(méi)有人想去看class文件的Byte code的它掂,大家都是想去看看這個(gè)class文件的源文件是什么樣的。
我們舉個(gè)最簡(jiǎn)單的例子:
這個(gè)類中虐秋,我們定義了一個(gè)很簡(jiǎn)單的testByteCode方法,里面定義了兩個(gè)變量用押,然后返回他們兩個(gè)的和靶剑。
現(xiàn)在有兩種方法來(lái)查看這個(gè)類的Byte Code:
第一種方法是用javap命令:
javap -c ByteCodeUsage.class
生成的結(jié)果如上所示。
第二種方法就是在IDEA中缎讼,選中class文件阐污,然后在view中選中show Bytecode:
我們看下輸出結(jié)果:
兩個(gè)的結(jié)果在顯示上面可能有細(xì)微的差異笛辟,但是并不影響我們后面對(duì)其的解析。
java Byte Code是怎么工作的
小師妹:F師兄手幢,能講解一下這些byte code到底是怎么工作的嗎忱详?
首先我們要介紹一下JVM的實(shí)現(xiàn)是基于棧的結(jié)構(gòu)的。為什么要基于棧的結(jié)構(gòu)呢匈睁?那是因?yàn)闂J亲钸m合用來(lái)實(shí)現(xiàn)function互相調(diào)用的。
我們?cè)倩仡櫼幌律厦娴膖estByteCode的字節(jié)碼胀蛮。里面有很多iconst,istore的東西粪狼,這些東西被稱作Opcode,也就是一些基于棧的操作指令再榄。
上面講了java bytecode的操作指令其實(shí)有很多個(gè)狡刘。下面我們列出這些指令的部分介紹:
實(shí)在是太多了困鸥,這里就不把所有的列出來(lái)了。
我們看到的指令名字其實(shí)是一個(gè)助記詞疾就,真實(shí)的Opcode是一個(gè)占用兩個(gè)字節(jié)的數(shù)字。
下面我們來(lái)詳細(xì)解釋一下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出棧厢拭,并存儲(chǔ)到變量1中。
第三步畦贸,iconst_2將int 2入棧。
第四步薄坏,istore_2將入棧的int 2出棧寨闹,并存儲(chǔ)到變量2中。
第五步繁堡,iload_1將變量1中的值入棧。
第六步椭蹄,iload_2將變量2中的值入棧。
第七步罩润,iadd將棧中的兩個(gè)變量出棧,并相加哨啃。然后將結(jié)果入棧。
第八步拳球,ireturn將棧中的結(jié)果出棧。
這幾步實(shí)際上完美的還原了我們?cè)趖estByteCode方法中定義的功能祝峻。
當(dāng)然我們只介紹了最賤的byte code命令,通過(guò)這些簡(jiǎn)單的命令可以組合成為更加復(fù)雜的java命令酬姆。
總結(jié)
本文介紹了java byte code的作用和具體的指令奥溺,并分析了一個(gè)簡(jiǎn)單的例子來(lái)做說(shuō)明。希望大家能夠掌握浮定。
本文的例子https://github.com/ddean2009/learn-java-base-9-to-20
本文作者:flydean程序那些事
本文鏈接:http://www.flydean.com/jvm-byte-code/
本文來(lái)源:flydean的博客
歡迎關(guān)注我的公眾號(hào):程序那些事,更多精彩等著您立美!