程序員使用Java語言實現(xiàn)累加求和的方法墅垮,將文件命名為Sample.java。
public class Sample {
public static void main(String[] args) {
System.out.println(sum(10));
}
private static int sum(int n) {
int res = 0;
for (int i = 1; i < n; i++) {
res += i;
}
return res;
}
}
程序員不想直接點(diǎn)擊運(yùn)行耕漱,使用javac編譯了Sample.java文件算色,可以看到Sample.java所在的目錄下,生成了Sample.class文件螟够。
那要是匯編語言灾梦,具體步驟應(yīng)該是怎樣的啊妓笙?
不過若河,什么是匯編語言?匯編語言其實和硬件息息相關(guān)寞宫,也就是脫離不了實際的硬件環(huán)境萧福,無法跨平臺運(yùn)行,因為匯編語言是人們用助記符表述CPU的動作辈赋。CPU結(jié)構(gòu)不一樣统锤,匯編語言調(diào)用的可能也不一樣。
那助記符是什么意思呢炭庙?匯編語言的每一行饲窿,表示對CPU的一個指令,其語法結(jié)構(gòu)是操作碼 + 操作數(shù)焕蹄。當(dāng)然也存在只有操作碼逾雄,例如ret,表示將處理返回到函數(shù)的調(diào)用源。
操作碼是對CPU的指令鸦泳,是動詞银锻,那操作碼是數(shù)據(jù),是存儲在CPU的寄存器做鹰,是賓語击纬。如mov a b; 表示將b的值賦值給a;add a b; 表示a同b的值相加钾麸,并將結(jié)果賦值給a更振。
那CPU是不是直接能懂這些助記符嗎?當(dāng)然不能饭尝。
我們知道計算上所有的地址和數(shù)據(jù)都是由0和1組成的肯腕,將匯編語言的那些助記符寫在文本文件上,進(jìn)行編譯的時候會調(diào)用本地計算機(jī)上的應(yīng)用钥平,名為masm.exe实撒,是一個編譯器。
將文本文件編譯成目標(biāo)文件涉瘾,此時的目標(biāo)文件成了機(jī)器語言知态,可以直接被本地的CPU所理解的,如果將這個目標(biāo)文件由別的計算機(jī)的不同系列CPU理解立叛,那可能是讀不懂肴甸,就好比如我們看不懂火星文。
那這個目標(biāo)文件可以被本地CPU可以直接解析運(yùn)行了嗎囚巴?可以是可以原在,但是會直接被報錯。
因為我們僅有這一個目標(biāo)文件彤叉,還不知道這個目標(biāo)文件和系統(tǒng)的庫文件哪些有關(guān)庶柿。所以,需要一個鏈接器秽浇,把相關(guān)的目標(biāo)文件組合成一個可以在特定平臺運(yùn)行的可執(zhí)行文件浮庐,如下圖:
庫文件名的后綴也是*.O或 *.OBJ。其中柬焕, *.ASM *.OBJ和 *.EXE是在dos或windows系統(tǒng)下的文件审残, *.S和 *.O是在以Linux內(nèi)核的系統(tǒng)下的文件后綴名,不過Linux內(nèi)核不靠文件后綴名來判斷這是什么文件斑举,一般靠文件屬性來判斷搅轿,可執(zhí)行文件在Linux內(nèi)核中沒有后綴名,用ls命令顯示這個文件是綠色就是可執(zhí)行文件富玷。
好了璧坟,如果是C/C++語言既穆,它的編譯過程應(yīng)該是怎么樣子的呢?
預(yù)處理 是將要包含(include)的文件插入原文件中雀鹃、將宏定義展開幻工、根據(jù)條件編譯命令選擇要使用的代碼,最后將這些代碼輸出到一個“.i”文件中等待進(jìn)一步處理黎茎;
轉(zhuǎn)換 是把C/C++代碼(比如上面的".i"文件)“翻譯”成匯編代碼囊颅;
編譯 是將用助記符號表示的匯編語言翻譯成符合一定格式的機(jī)器語言;
鏈接 是將匯編生成的OBJ文件傅瞻、系統(tǒng)庫的OBJ文件踢代、庫文件鏈接起來,最終生成可以在特定平臺運(yùn)行的可執(zhí)行程序俭正。
好了,寫著寫著忘記Java程序的正事了焙畔。
大家所說的Java掸读,有兩個層面意思,一個是作為編程語言的Java宏多,另一個是作為程序運(yùn)行環(huán)境的Java儿惫。這就是Java的特殊所在,特殊就特殊在Java有Java虛擬機(jī)伸但。
Java程序也需要編譯肾请,但是沒有編譯成機(jī)器語言,而是編譯成字節(jié)碼文件更胖,然后在Java虛擬機(jī)用解釋的方式執(zhí)行字節(jié)碼铛铁。
編譯 是將Java源代碼“翻譯”為Java虛擬機(jī)可執(zhí)行的字節(jié)碼文件却妨,保存到硬盤上;
加載 是將生成在內(nèi)存上的字節(jié)碼文件的副本彪标,加載到Java虛擬機(jī)上;
Java虛擬機(jī) 加載后字節(jié)碼后捞烟,執(zhí)行方式有兩種薄声,一種是即時編譯器,另一種是字節(jié)碼解釋器题画,如下圖:
即時編譯和解釋執(zhí)行的區(qū)別如下:
解釋執(zhí)行:將編譯好的字節(jié)碼一行一行地翻譯為機(jī)器碼執(zhí)行苍息。
編譯執(zhí)行:以方法為單位廓奕,將字節(jié)碼一次性翻譯為機(jī)器碼后執(zhí)行抱婉。
軟件 是指Java虛擬機(jī)對于系統(tǒng)來說,是一個應(yīng)用桌粉,是用某個高級語言編寫的應(yīng)用蒸绩。
當(dāng)然铃肯,Java虛擬機(jī)對Java程序來說,是一個運(yùn)行的環(huán)境押逼。我們可以對比分析一下,把Java源代碼想象成匯編語言源代碼咙冗,字節(jié)碼想象成本地CPU可執(zhí)行的機(jī)器語言漂彤,Java虛擬機(jī)想象成本地CPU雾消。
所以這就是為什么說Java是跨平臺的挫望,因為Java虛擬機(jī)是一個應(yīng)用嘛。不過媳板,不同的系統(tǒng),應(yīng)用也是不同的破讨,所以系統(tǒng)不同奕纫,Java虛擬機(jī)也是不同的,但是字節(jié)碼文件可以不變的若锁,可以直接到其它不同系統(tǒng)上的虛擬機(jī)解析執(zhí)行的。
Java虛擬機(jī)運(yùn)行的是字節(jié)碼又固,字節(jié)碼對Java來說是十六進(jìn)制;本地CPU執(zhí)行的是機(jī)器碼(機(jī)器語言)乏冀,機(jī)器碼對系統(tǒng)來說是二進(jìn)制洋只。不過辆沦,字節(jié)碼文件放在本地是0和1組成的昼捍,只是不能被本地系統(tǒng)解析執(zhí)行,需要Java虛擬機(jī)即時編譯或解釋執(zhí)行妒茬。
“百聞不如一見”蔚晨,我們看看*.class用記事本打開會是怎么樣的。
這打開是亂碼的懊蟆?這是因為以class為后綴名的字節(jié)碼文件在Java中保存的是十六進(jìn)制浩考,那我們要看十六進(jìn)制如何看呢被盈?
我們可以用Sublime Text 3打開字節(jié)碼文件,但打開之前Sublime Text 3需要安裝HexViewer插件害捕,才可以看十六進(jìn)制的闷畸,具體安裝過程可以到網(wǎng)上搜索。打開之后盾沫,如下圖所示:
可以看到所有的數(shù)字都是十六進(jìn)制的殿漠,接下來下一步就加載到Java虛擬機(jī)上去了,具體用即時編譯的還是解釋執(zhí)行的蕾哟,或者在大項目中即時編譯和解釋執(zhí)行都是可以共同打配合的莲蜘,因為Java虛擬機(jī)在不同的場景下用的是不同的優(yōu)化手段。
喜歡本文的朋友票渠,微信搜索「算法無遺策」公眾號,收看更多精彩的算法動畫文章