一個(gè).java文件的"沉浮"之路
本文全為原創(chuàng)內(nèi)容,轉(zhuǎn)載請(qǐng)注明出處:http://www.reibang.com/p/af78a314c6fc
1:引言:
由于昨天的網(wǎng)絡(luò)問題请梢,導(dǎo)致分享做的不是特別好力穗。所以老薛這里寫了一份分
享的筆記毅弧,希望可以幫助那些沒有聽課的同學(xué)稍稍彌補(bǔ)一下。
昨天的分享大概分為一下幾個(gè)模塊來講解的:
i:分享初衷
ii:分享內(nèi)容大綱
iii:建議
iv:一個(gè).java文件的沉浮之路
a:什么是計(jì)算機(jī)当窗?
b:計(jì)算機(jī)發(fā)展歷史
c:.java文件如何變?yōu)?class文件
d:.class文件如何被JVM加載形真,加載內(nèi)容如何解析
e:jvm和操作系統(tǒng)和底層硬件的簡單交互。
2:分享初衷:
很多人遇到一個(gè)很尷尬的問題:一看就會(huì)超全,一問就懵咆霜,一敲就傻。
新技術(shù)層出不窮,到底學(xué)習(xí)什么救军?如何取舍拷泽。
業(yè)務(wù)代碼很多聋迎,編寫代碼不夠優(yōu),不知道如何增加自己的硬編碼實(shí)例。
每天都很忙谷浅,不知道如何利用自己的碎片化時(shí)間武裝自己的知識(shí)體系蛹锰。
基于以上內(nèi)容竹海,希望能夠找到一些技術(shù)。分享給大家,而這些技術(shù)必須具備如下特征:
可能實(shí)用價(jià)值不高,但是希望能夠在未來很長一段時(shí)間對(duì)你而言都有幫助
可以很好的和目前的編碼統(tǒng)一起來,不能由于新的技術(shù)加入,導(dǎo)致和目前的學(xué)習(xí)工作沒有關(guān)系
3:分享內(nèi)容大綱
基于剛才的內(nèi)容,我大概在自己有限的學(xué)習(xí)數(shù)據(jù)庫中整理了一下。我會(huì)在以下內(nèi)容開始分享:
‘瞎’侃計(jì)算機(jī)組成與系統(tǒng)結(jié)構(gòu)
‘胡’說數(shù)據(jù)結(jié)構(gòu)和算法
‘嗨’聊計(jì)算機(jī)網(wǎng)絡(luò)
實(shí)戰(zhàn)編碼:
你真的會(huì)寫代碼嗎? 如何寫出優(yōu)雅高效的代碼!
什么是面向?qū)ο罅宀恚磕軌蛲ㄟ^面向?qū)ο蟮姆绞饺タ创龁栴}纺且,而非將對(duì)象作為一個(gè)Data
手撕系列!能夠通過java 寫一些好玩的內(nèi)容。比如服務(wù)器,jvm,Struts坠陈,Spring等
4:建議
大家也能看到我這里所有的內(nèi)容都是加了一個(gè)字贮匕,所以我盡自己的最大能力把這個(gè)東西分享的好玩一點(diǎn)壤追。并且也希望大家意識(shí)到,我和大家分享的內(nèi)容只是我的理解,千萬不能全信。
我希望如果你真的想和我一起增強(qiáng)自己的知識(shí)脈絡(luò),最好能做到以下幾件事情:
存疑+堅(jiān)持+廣而告之+參與感
1:存疑 任何知識(shí)傳播都是會(huì)存在差異性的赵讯。所以千萬不能全信,要有自己的主觀判斷。
但是基于28法則牙寞,大概率我聊的80%內(nèi)容你應(yīng)該是要信的缝驳。嘿嘿~~
2:堅(jiān)持 這個(gè)就不談了,一句話總結(jié),世界上最難的事情就是堅(jiān)持报账,最簡單的事情就是放棄抖剿。
3:廣而告之 我希望我分享的內(nèi)容你能夠有一個(gè)落地,筆記匣沼,博客刀脏,一定要形成一個(gè)書面的內(nèi)容。
4:參與感 千萬記得仙逻,免費(fèi)的東西是最貴的萌踱,因?yàn)楹馁M(fèi)了你的時(shí)間粉铐,所以我會(huì)努力做的更好溪胶,而
如果你也認(rèn)可這件事情桑逝,請(qǐng)一定要參與進(jìn)來拘荡,而不是作為一個(gè)旁觀者驶兜。
如果這些你都能做到唉韭,那么就和我一起并肩前行吧驾胆!??
5:.java文件的沉浮之路
接下來進(jìn)入到這次分享的主要內(nèi)容,看看小J同學(xué)在執(zhí)行過程中都經(jīng)歷了什么谁鳍!??
編寫一個(gè).java文件然后依次編譯,執(zhí)行输硝。過程如下:
5-1:編寫一個(gè).java文件
5-2:通過javac和java指令執(zhí)行
這個(gè)運(yùn)行過程就不贅述了朵你,我們直接上圖:
5-3:揭秘第一部分.java文件如何變?yōu)?class文件
編譯器遵守什么規(guī)則俘种,將.java文件編譯為.class文件
5-3-1:編譯規(guī)則:
5-3-2:詞法分析:
.java文件編譯為.class文件時(shí),先進(jìn)行詞法分析 如下圖:
總結(jié):這里著重解析.java文件編寫的第5行代碼艾船,可以將例子后的代碼理解為java中的第5行代碼。
在進(jìn)行詞法分析時(shí),會(huì)將內(nèi)容進(jìn)過線性分析,變成一張符號(hào)表角钩。符號(hào)表為上圖中的右側(cè)內(nèi)容。右側(cè)的表格內(nèi)容由三部分構(gòu)成:
1: 唯一表示 1,2,3 類似符號(hào)表中的地址編號(hào)
2: 變量名稱 比如:標(biāo)識(shí)符position,操作符號(hào) + 等等
3: 變量的值
由詞法分析我們將整個(gè).java文件中的內(nèi)容變成了一張表。接下來:
5-3-2:語法分析:
詞法分析變?yōu)橐粡埛?hào)表农渊,繼續(xù)語法分析
總結(jié):通過形成的符號(hào)表唇辨,會(huì)生成一顆語法二叉樹摄凡。在這里有一個(gè)很有意思的東西,就是我們觀察二叉樹,發(fā)現(xiàn)符號(hào)作為了根節(jié)點(diǎn)败砂,而且+號(hào)的節(jié)點(diǎn)在*
號(hào)的節(jié)點(diǎn)之上祭隔。這里解析時(shí)倒敘解析桩撮。那么為什么*
號(hào)會(huì)在+號(hào)節(jié)點(diǎn)之下右钾,其實(shí)如果你要定義一個(gè)語言時(shí)邢羔,一定要告知這個(gè)語言一定是一個(gè)形式化的,這個(gè)形式化的方式可以通過BNF
定義败许。在形式化的定義規(guī)則里王带,*
號(hào)的優(yōu)先級(jí)別高于+
號(hào)。
`BNF`巴科斯范式(BNF: Backus-Naur Form 的縮寫)市殷。引入一種形式化符號(hào)來描述給定語言的
語法愕撰。就是通過BNF來定義語言的語法,按照定義的規(guī)則去形成編譯時(shí)的語法分析醋寝。
擴(kuò)展:
在雙引號(hào)中的字("word")代表著這些字符本身搞挣。而double_quote用來代表雙引號(hào)。
在雙引號(hào)外的字(有可能有下劃線)代表著語法部分音羞。
尖括號(hào)( < > )內(nèi)包含的為必選項(xiàng)囱桨。
方括號(hào)( [ ] )內(nèi)包含的為可選項(xiàng)。
大括號(hào)( { } )內(nèi)包含的為可重復(fù)0至無數(shù)次的項(xiàng)黄选。
豎線( | )表示在其左右兩邊任選一項(xiàng)蝇摸,相當(dāng)于"OR"的意思。
::= 是“被定義為”的意思办陷。
這部分內(nèi)容主要涉及編譯原理,有興趣可以自行參考:
5-3-3:java的bnf定義:
總結(jié):大家可以根據(jù)上面的bnf擴(kuò)展語法律歼,我們發(fā)現(xiàn)java的bnf定義如果要聲明一個(gè)類class_declaration
被這樣定義:<modifier>
需要編寫一個(gè)修飾符民镜,修飾符的定義:modifier:=="public"|"private"...
,這里我們可知定義類的時(shí)候必須時(shí)這些關(guān)鍵詞,關(guān)鍵詞已經(jīng)給出來了险毁。如果你寫的class的修飾符不是modifier定義的詞制圈,那么編譯時(shí)語法就會(huì)報(bào)錯(cuò)。依次類推畔况。“class”
是必須要寫的鲸鹦,同理如果定義類是不寫則編譯語法報(bào)錯(cuò)。在到后面的identifier
跷跪,也是有對(duì)應(yīng)定義的值:identifier:=="a..z,$,_"<"...."
馋嗜。其實(shí)這個(gè)不就是java規(guī)范中對(duì)于標(biāo)識(shí)符的定義嗎?不能以數(shù)字開頭吵瞻。其實(shí)要編寫一門語言葛菇。必須要有形式化的bnf定義甘磨。
5-3-4:語義分析:
語義分析,注意計(jì)算機(jī)的語義分析一定要知道眯停,計(jì)算機(jī)語言不能存在
二意性
济舆。這個(gè)和自然語言不通。
總結(jié):在語義分析是會(huì)做類型檢查莺债,控制流檢查滋觉,類型檢查等等。我們回想之前的java程序齐邦,在進(jìn)行*
發(fā)運(yùn)算時(shí)椎瘟,由于rate時(shí)float類型,而60時(shí)一個(gè)int類型的字面值
侄旬。此時(shí)會(huì)將60這個(gè)int類型轉(zhuǎn)換為float肺蔚,其實(shí)類型轉(zhuǎn)換是在編譯時(shí)發(fā)生的±芨幔回想我們編寫程序時(shí)的基本數(shù)據(jù)類型的類型轉(zhuǎn)換錯(cuò)誤宣羊,是不是發(fā)生在編譯階段呢?
5-3-5:中間代碼生成汰蜘,優(yōu)化以及生產(chǎn)對(duì)應(yīng)的目標(biāo)文件:
產(chǎn)生最后的目標(biāo)文件
總結(jié):經(jīng)過語義分析的語法二叉樹開始準(zhǔn)備生產(chǎn)對(duì)應(yīng)的中間代碼族操。這里我們發(fā)現(xiàn)第一行代碼:temp1=int_to_float(60)
,注意苛坚,這里的語法二叉樹相當(dāng)于只是在二叉樹上給了一個(gè)標(biāo)示,說明60需要做類型轉(zhuǎn)換色难。而將60轉(zhuǎn)換為float這個(gè)是在生成中間代碼中得到實(shí)際體現(xiàn)的泼舱。第二行代碼temp2=id3*temp1
,id3是什么意思呢?如果你還記得符號(hào)表的組成部分枷莉,那么這個(gè)應(yīng)該不能猜出來娇昙。它就是符號(hào)表中的唯一表示。id為3的符號(hào)表笤妙,id為3的符號(hào)表中的變量為rate冒掌,對(duì)應(yīng)的值為3.1。然后繼續(xù)操作蹲盘,直到中間代碼生成結(jié)束股毫。
我們發(fā)現(xiàn)中間的代碼有一些代碼是不需要做的,這里做代碼優(yōu)化召衔。將一部分不需要的代碼省略铃诬。
最后生成目標(biāo)的代碼,這里因?yàn)榻貓D不是java代碼,所以最后顯示的目標(biāo)文件是一個(gè)匯編指令氧急。movl id3 R2
颗胡,意思就是將id3的值也就是rate中的值存儲(chǔ)到寄存器R2中,MUL #60.0吩坝,R2
毒姨,意思就是將60.0和R
2寄存器中的值進(jìn)行相乘,將結(jié)果存放到R2寄存器钉寝。依次類推弧呐。movl R1,id1
,意思將R1寄存器中的值存儲(chǔ)到id1中嵌纲,id1其實(shí)就是變量position俘枫,值為R1寄存器的值。
到此逮走,我們的.class文件也就生成了鸠蚪。
5-4:揭秘第二部分.class文件如何被java指令開始解析執(zhí)行的。
5-4-1:操作系統(tǒng)執(zhí)行可執(zhí)行程序师溅,調(diào)度計(jì)算機(jī)
5-4-1-1:計(jì)算機(jī)結(jié)構(gòu):
總結(jié):
1:我們編寫的一個(gè)不論是.java文件編譯也好墓臭,解釋執(zhí)行也罷蘸鲸。首先都是存儲(chǔ)到磁盤上的。
2:我們通過鍵盤輸入javac窿锉,開始執(zhí)行編譯指令酌摇。
3:javac指令被操作系統(tǒng)讀取,然后操作系統(tǒng)調(diào)度計(jì)算機(jī)嗡载,計(jì)算機(jī)中的io總線識(shí)別到本次調(diào)度指令窑多,
然后通過io橋通知cpu,cpu將磁盤上的.java文件通過io橋鏈接io總線鼻疮,將磁盤數(shù)據(jù)讀取到主存當(dāng)中怯伊。
4:然后.java文件準(zhǔn)備開始編譯。主存中的數(shù)據(jù)會(huì)被讀取到cpu中的高速緩沖設(shè)備中判沟,進(jìn)行編譯。
5:編譯之后的.class文件崭篡,通過io橋鏈接io總線挪哄,被寫出到磁盤。
6:如果編譯時(shí)有語法錯(cuò)誤琉闪,那么cpu通過io橋迹炼,鏈接io總線上的圖形適配器,顯示報(bào)錯(cuò)信息
當(dāng)然這里鏈接以及調(diào)度的方式如果深究還是挺復(fù)雜的,暫時(shí)我們不做討論斯入,簡單點(diǎn)就是"連找發(fā)"三元素理論砂碉。如果你不是本專業(yè)的,其實(shí)目前來講這個(gè)對(duì)于我們不太重要刻两,后續(xù)老薛會(huì)稍微展開再聊聊增蹭。當(dāng)然,也可以參考下面的博文:參考博文地址磅摹。
這里之所以采用IO總線
的方式鏈接各個(gè)設(shè)備滋迈,原因是很方便我可以刪除,增加設(shè)備户誓,你如果使用輻射式鏈接饼灿,就要主機(jī)連接各個(gè)設(shè)備,每個(gè)設(shè)備都有一套自己的控制線路帝美,很麻煩碍彭。我們可以不防將總線理解為一個(gè)鏈表,而輻射式理解為數(shù)組悼潭。并且總線很清晰能夠規(guī)劃出各個(gè)設(shè)備之間的關(guān)系庇忌,但是輻射的話,設(shè)備的相連關(guān)系會(huì)很復(fù)雜女责。
5-4-1-2:計(jì)算機(jī)結(jié)構(gòu)遺留問題:
總結(jié):計(jì)算機(jī)的產(chǎn)生是基于圖靈計(jì)算模型
漆枚,而根據(jù)數(shù)據(jù)和指令集存放位置的不同分為了:芬諾依曼結(jié)構(gòu)
,哈弗結(jié)構(gòu)
。有興趣大家可以稍微展開看看抵知,老薛后續(xù)會(huì)展開來聊這兩個(gè)東西墙基。
5-4-2:.class文件如何執(zhí)行
注意:jvm的加載過程不是本次分享的內(nèi)容,老薛后續(xù)會(huì)展開聊刷喜,我們這次主要聊的點(diǎn)是残制,為什么jvm虛擬機(jī)可以去執(zhí)行.class文件,這個(gè)文件中到底有什么東西掖疮?
總結(jié):在整個(gè)執(zhí)行過程中初茶,我們發(fā)現(xiàn)一個(gè)程序編譯為字節(jié)碼文件之后,其實(shí)就是一大堆的二進(jìn)制數(shù)據(jù)浊闪。這里字節(jié)碼展示是通過16進(jìn)制查看的恼布。然后進(jìn)過jvm加載,解析搁宾,在jvm中構(gòu)建一個(gè)運(yùn)行時(shí)結(jié)構(gòu)折汞,然后開始執(zhí)行。我們接下來就編寫程序盖腿,以及通過反匯編指令去深究一下.class文件中到底有哪些內(nèi)容爽待。
5-4-2-1:將我們之前編寫的Demo.java編譯之后進(jìn)行讀人鹜:
注意:通過流的方式將Demo.class讀取進(jìn)來,且按照16進(jìn)制顯示數(shù)據(jù)如下
下圖是16進(jìn)制對(duì)應(yīng)一覽表
總結(jié):
1: u:代表無符號(hào)位鸟款,u4代表無符號(hào)4個(gè)字節(jié)用來代表魔數(shù)膏燃。意思憑什么能夠確定當(dāng)前文件是.class呢?
由魔數(shù)確定何什。也就意味著.class文件的魔數(shù)為`cafebabe`,俗稱`咖啡寶貝`组哩。你也可以讀取一下
jpg或者其他類型的文件的前4個(gè)字節(jié)是什么。
2: 后續(xù)的u2富俄,無符號(hào)位2個(gè)字節(jié)代表次版本號(hào)禁炒,那就是以為當(dāng)前次版本號(hào)為0
3: 后續(xù)的u2,無符號(hào)位2個(gè)字節(jié)代表主版本號(hào)霍比,那么這里是是00 35幕袱,也就是53,也就是jdk9.
JDK各個(gè)版本對(duì)應(yīng)關(guān)系
JDK 1.10= 54 JDK 1.9 = 53 JDK 1.8 = 52 JDK 1.7 = 51 JDK 1.6 = 50
JDK 1.5 = 49 JDK 1.4 = 48 JDK 1.3 = 47 JDK 1.2 = 46 JDK 1.1 = 45
4:擴(kuò)展一下悠瞬,這里采用的是大端模式们豌,關(guān)于大小端我之前有聊過。大家也可以參考資料再看看浅妆。
其實(shí)采用大端有個(gè)地方特別好望迎,這樣我們再解析這個(gè)16進(jìn)制內(nèi)容就稍微方便一點(diǎn),直接可以省略開頭為
0的字節(jié)凌外。
5: 后續(xù)的u2辩尊,無符號(hào)2個(gè)字節(jié)代表常量池個(gè)數(shù),注意這里的常量池和我們一般意義下的內(nèi)存中的常量池
還是有區(qū)別的康辑,這里的常量池是包括所有字面常量摄欲,比如變量,類名疮薇,方法名等等胸墙。這里是00 30,那么
也就也為者有48個(gè)常量按咒,往后數(shù)48個(gè)字節(jié)迟隅,都代表的是常量值。這里注意励七,48要加上本身常量池的個(gè)數(shù) 也會(huì)占空間智袭,也就以為著一共只有47個(gè)常量。
6: 再往后的u2掠抬,代表的是訪問標(biāo)志补履,該類的修飾符,以及是否可以使用比如多態(tài)剿另,如果可以使用那么意 味著就可以使用invokespecial,這個(gè)是java字節(jié)碼調(diào)用指令,代表可以調(diào)用私有實(shí)例方法雨女,構(gòu)造器以 及使用super調(diào)用父類的實(shí)例方法等谚攒。剩下的依次類推。
大小端資料參考
通過javap -c -v反匯編氛堕,查看內(nèi)容:
以下內(nèi)容中兩個(gè)`中間的內(nèi)容是老薛寫的注釋
Classfile /Users/iongst/Desktop/Demo.class `class文件所在地址`
Last modified 2018年9月8日; size 884 bytes `最后一次修改時(shí)間以及大小`
MD5 checksum 8619092419ab6d93efe90de9a29f5e36 `md5值`
Compiled from "Demo.java" `編譯自那個(gè)文件`
public class Demo `類的聲明`
minor version: 0 `次版本號(hào)`
major version: 53 `主版本號(hào) jdk9`
flags: (0x0021) ACC_PUBLIC, ACC_SUPER `訪問標(biāo)志馏臭,acc_public 代表是public修飾,acc_super 代表可以使用invokespecial `
this_class: #7 // Demo `thisclass thisclass指向了#7的地址讼稚,可以看看#7是什么`
super_class: #8 // java/lang/Object
interfaces: 0, fields: 0, methods: 2, attributes: 3 `對(duì)照進(jìn)制一覽表括儒,分別代表接口個(gè)數(shù)為0,沒有實(shí)現(xiàn)接口
fields字段個(gè)數(shù)為0 方法個(gè)數(shù)2個(gè)锐想,屬性有3個(gè)帮寻。問題2:這里的fields和attributes代表什么含義?`
Constant pool: `常量池`
#1 = Methodref #8.#17 // java/lang/Object."<init>":()V
#2 = Float 3.1f
#3 = Float 60.0f
#4 = Fieldref #18.#19 // java/lang/System.out:Ljava/io/PrintStream;
#5 = InvokeDynamic #0:#23 // #0:makeConcatWithConstants:(F)Ljava/lang/String;
#6 = Methodref #24.#25 // java/io/PrintStream.println:(Ljava/lang/String;)V
#7 = Class #26 // Deme `存儲(chǔ)了#26 繼續(xù)往下找`
#8 = Class #27 // java/lang/Object
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 main
#14 = Utf8 ([Ljava/lang/String;)V
#15 = Utf8 SourceFile
#16 = Utf8 Demo.java
#17 = NameAndType #9:#10 // "<init>":()V
#18 = Class #28 // java/lang/System
#19 = NameAndType #29:#30 // out:Ljava/io/PrintStream;
#20 = Utf8 BootstrapMethods
#21 = MethodHandle 6:#31 // REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
#22 = String #32 // 計(jì)算結(jié)果是:\u0001
#23 = NameAndType #33:#34 // makeConcatWithConstants:(F)Ljava/lang/String;
#24 = Class #35 // java/io/PrintStream
#25 = NameAndType #36:#37 // println:(Ljava/lang/String;)V
#26 = Utf8 Demo `就存儲(chǔ)了類名赠摇,問題1:為什么要存儲(chǔ)類名固逗?`
#27 = Utf8 java/lang/Object
#28 = Utf8 java/lang/System
#29 = Utf8 out
#30 = Utf8 Ljava/io/PrintStream;
#31 = Methodref #38.#39 // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
#32 = Utf8 計(jì)算結(jié)果是:\u0001
#33 = Utf8 makeConcatWithConstants
#34 = Utf8 (F)Ljava/lang/String;
#35 = Utf8 java/io/PrintStream
#36 = Utf8 println
#37 = Utf8 (Ljava/lang/String;)V
#38 = Class #40 // java/lang/invoke/StringConcatFactory
#39 = NameAndType #33:#44 // makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
#40 = Utf8 java/lang/invoke/StringConcatFactory
#41 = Class #46 // java/lang/invoke/MethodHandles$Lookup
#42 = Utf8 Lookup
#43 = Utf8 InnerClasses
#44 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
#45 = Class #47 // java/lang/invoke/MethodHandles
#46 = Utf8 java/lang/invoke/MethodHandles$Lookup
#47 = Utf8 java/lang/invoke/MethodHandles
`常量池個(gè)數(shù)一共有47個(gè),所以雖然我們查看是48個(gè)是包含本身常量池的1的所以是48`
{
public Demo();
descriptor: ()V
flags: (0x0001) 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 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=1
0: bipush 10
2: istore_1
3: ldc #2 // float 3.1f
5: fstore_2
6: iload_1
7: i2f
8: fload_2
9: ldc #3 // float 60.0f
11: fmul
12: fadd
13: fstore_3
14: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
17: fload_3
18: invokedynamic #5, 0 // InvokeDynamic #0:makeConcatWithConstants:(F)Ljava/lang/String;
23: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
26: return
LineNumberTable:
line 3: 0
line 4: 3
line 5: 6
line 6: 14
line 7: 26
}
SourceFile: "Demo.java"
InnerClasses:
public static final #42= #41 of #45; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
0: #21 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
Method arguments:
#22 計(jì)算結(jié)果是:\u0001
文末總結(jié):
大家如果真的能耐著性子把這個(gè)文章看完藕帜,在我看來真的很厲害了烫罩。后面也埋了一些坑,比如后面的方法調(diào)用洽故,我這里一共添加了108號(hào)反編譯之后的代碼贝攒,后面很多代碼老薛也沒有講解,這個(gè)作為后續(xù)內(nèi)容时甚。那么我們是不是可以這樣理解隘弊,如果我們將一個(gè).class文件讀取進(jìn)來之后,按照對(duì)照一覽表
開始解析撞秋,只要我們能夠分析出來運(yùn)行時(shí)數(shù)據(jù)區(qū)长捧,我們完全是可以自己寫一個(gè)jvm的。這是沒有問題哦吻贿。
如果大家有什么問題串结,大家可以在文末或者是微信私聊老薛。老薛微信 lukun0402
本章內(nèi)容參考書籍資料:《編譯原理》 《深入理解計(jì)算機(jī)系統(tǒng)》 《碼農(nóng)翻身》
課后作業(yè):
- 我們知道cpu是個(gè)快速設(shè)備舅列,內(nèi)存稍次之肌割,磁盤排第三,如果你走網(wǎng)絡(luò)會(huì)更慢帐要,那么整個(gè)執(zhí)行過程其實(shí)是通過最低速設(shè)備決定的把敞,你有什么比較好的辦法能夠解決這個(gè)問題嗎?
- 給大家布置了數(shù)據(jù)結(jié)構(gòu)的系統(tǒng)榨惠,如果興趣的同學(xué)可以做一做奋早。作業(yè)地址盛霎。也可以復(fù)制鏈接:https://github.com/iongst/dataStructure
- 在作業(yè)中也留了一些作業(yè),編寫數(shù)據(jù)結(jié)構(gòu)時(shí)耽装,在老薛寫的接口中愤炸,已經(jīng)留了思考的彩蛋,大家努力查找吧掉奄。