|
機(jī)器語(yǔ)言由非常簡(jiǎn)單的指令組成,計(jì)算機(jī)的CPU可以直接執(zhí)行這些指令。幾乎所有的程序都是用Java、Fortran或C++這樣的高級(jí)語(yǔ)言編寫的。由高級(jí)語(yǔ)言編寫的程序不能被任何計(jì)算機(jī)直接執(zhí)行。首先,必須將其翻譯成機(jī)器語(yǔ)言。這種翻譯由一種稱為編譯器的程序完成,編譯器將高級(jí)語(yǔ)言翻譯成可執(zhí)行的機(jī)器語(yǔ)言程序。當(dāng)翻譯完成后,機(jī)器語(yǔ)言的程序就可以運(yùn)行任意多次。當(dāng)然,只能在同一種類型的計(jì)算機(jī)上運(yùn)行(這是因?yàn)槊糠N類型的計(jì)算機(jī)都有自己獨(dú)立的計(jì)算機(jī)語(yǔ)言)。如果該程序需要在另一種類型的計(jì)算機(jī)上運(yùn)行,就必須使用另一種編譯器重新翻譯成對(duì)應(yīng)的機(jī)器語(yǔ)言。 還有另一種編譯高級(jí)語(yǔ)言的程序的方式。除了使用編譯器一次性編譯程序外,還可以使用解釋器,按需求逐指令翻譯程序。解釋器也是一個(gè)程序,其扮演的角色和CPU類似,還有一個(gè)獲取并執(zhí)行(fetch-and-execute)循環(huán)。為了執(zhí)行程序,解釋器在一個(gè)循環(huán)中運(yùn)行,重復(fù)從程序中讀取每條指令,根據(jù)這條指令來(lái)決定要做些什么,然后執(zhí)行對(duì)應(yīng)的機(jī)器語(yǔ)言指令。 使用解釋器的過(guò)程就是在執(zhí)行高級(jí)語(yǔ)言的程序。例如,Lisp語(yǔ)言通常使用解釋器執(zhí)行,而不是編譯器。然而,解釋器還有其他目的:即可以在不同類型的計(jì)算機(jī)上使用同一種機(jī)器語(yǔ)言程序。例如,原來(lái)有一種家用計(jì)算機(jī)稱為Commodore 64或“C64”。但在實(shí)際中并沒(méi)有發(fā)現(xiàn)C64,不過(guò)發(fā)現(xiàn)了在其他計(jì)算機(jī)甚至瀏覽器中運(yùn)行的程序可以模擬一個(gè)C64。這樣的模擬器可以通過(guò)扮演C64機(jī)器語(yǔ)言的解釋器來(lái)運(yùn)行C64程序。 Java的設(shè)計(jì)者巨頂將編譯和解釋結(jié)合起來(lái)。Java編寫的程序編譯成機(jī)器語(yǔ)言,但并不存在使用這種機(jī)器語(yǔ)言的就是就是。這種“虛擬”的就是就是成為Java虛擬機(jī)(JVM)。JVM的機(jī)器語(yǔ)言成為Java字節(jié)碼。Java字節(jié)碼不僅可以用于虛擬的計(jì)算機(jī),也可以用于真實(shí)的計(jì)算機(jī)。但實(shí)際上,使用虛擬機(jī)成就了Java的一個(gè)賣點(diǎn):即Java字節(jié)碼可以在任何計(jì)算機(jī)上使用。所有這些計(jì)算機(jī)只需要一個(gè)Java字節(jié)碼的解釋器。這種解釋器模擬模擬JVM,就像C64模擬器模擬Commodore 64計(jì)算機(jī)那樣。(屬于JVM還可用于表示Java字節(jié)碼解釋器程序完成模擬的過(guò)程。所以我們說(shuō),若想運(yùn)行Java程序,必須要有JVM。從技術(shù)上來(lái)講,說(shuō)解釋器實(shí)現(xiàn)了JVM比解釋器就是JVM要更加正確一些。) 當(dāng)然,不同類型的計(jì)算機(jī)需要不同的Java字節(jié)碼解釋器,但每當(dāng)一種計(jì)算機(jī)有了Java字節(jié)碼解釋器后,就可以運(yùn)行任何Java字節(jié)碼程序,這樣的程序也可以運(yùn)行在任何裝有Java解釋器的計(jì)算機(jī)上。這正是Java的本質(zhì)屬性:相同編譯后的程序可以運(yùn)行在許多不同的計(jì)算機(jī)上。 但為什么能在所有地方都使用中間的Java字節(jié)碼?為什么不直接分發(fā)原來(lái)的Java程序,讓每個(gè)人自行將其編譯成需要運(yùn)行的計(jì)算機(jī)上的機(jī)器語(yǔ)言。其中的原因有很多。首先,需要有一個(gè)理解Java這門高級(jí)語(yǔ)言的編譯器。這種編譯器本身就是一個(gè)復(fù)雜的程序。另一方面,Java字節(jié)碼解釋器,是一個(gè)相對(duì)來(lái)說(shuō)較小,簡(jiǎn)單的程序。因此,很容易為一種新類型的計(jì)算機(jī)編寫一個(gè)字節(jié)碼解釋器。完成這一步后,新計(jì)算機(jī)就可以運(yùn)行任何編譯過(guò)的Java程序。而為同樣的計(jì)算機(jī)編寫一個(gè)Java編譯器卻困難的多。 除此之外,有些Java程序需要從網(wǎng)絡(luò)下載。 這會(huì)導(dǎo)致顯而易見的安全問(wèn)題:我們不想運(yùn)行會(huì)損害計(jì)算機(jī)或文件的程序。字節(jié)碼解釋器在計(jì)算機(jī)和下載的程序之間充當(dāng)一個(gè)緩存。在實(shí)際中,運(yùn)行的是解釋器,這樣是間接的運(yùn)行下載下來(lái)的程序。解釋器可以阻止下載下來(lái)的程序中含有的潛在的危險(xiǎn)行為。 在Java剛問(wèn)世不久時(shí),人們經(jīng)常批評(píng)Java很慢。這是因?yàn)镴ava字節(jié)碼由解釋器運(yùn)行,看上去Java字節(jié)碼永遠(yuǎn)不會(huì)像編譯成機(jī)器語(yǔ)言的語(yǔ)言那樣快(后者實(shí)際上是在運(yùn)行計(jì)算機(jī)自身的機(jī)器語(yǔ)言)。但是,通過(guò)即時(shí)(JIT)編譯器執(zhí)行Java字節(jié)碼可以在很大程度上克服這一缺點(diǎn)。即時(shí)編譯器將Java字節(jié)碼翻譯成本地機(jī)器語(yǔ)言。其在執(zhí)行程序時(shí)完成這一步驟。對(duì)于普通的解釋器,輸入到即時(shí)編譯器的是Java字節(jié)碼,其任務(wù)是執(zhí)行這個(gè)程序。但在執(zhí)行時(shí),還會(huì)將其中的某些部分翻譯成機(jī)器語(yǔ)言。翻譯的部分執(zhí)行起來(lái)比解釋執(zhí)行要快得多。由于在程序運(yùn)行時(shí),某些部分可能會(huì)多次執(zhí)行,所以即時(shí)編譯器可以有效的減少總體執(zhí)行時(shí)間。 這里需要提醒一下,Java和Java字節(jié)碼之間沒(méi)有必然的聯(lián)系。Java編寫的程序依然可以編譯成真實(shí)計(jì)算機(jī)的機(jī)器語(yǔ)言。其他語(yǔ)言編寫的程序可以編譯成Java字節(jié)碼。但Java和Java字節(jié)碼之間的組合是不依賴特定平臺(tái)、安全、網(wǎng)絡(luò)兼容的,這樣允許用戶以現(xiàn)代的高級(jí)面向?qū)ο蟮恼Z(yǔ)言編寫程序。 在過(guò)去幾年,有許多新語(yǔ)言或已存在的語(yǔ)言都編譯成Java字節(jié)碼。編譯后的字節(jié)碼程序可以用標(biāo)準(zhǔn)的JVM運(yùn)行。專門為JVM開發(fā)的新語(yǔ)言包括Groovy、Clojure、Processing。面向JVM的Jython和JRuby分別表示的已有的Python和Ruby。這些語(yǔ)言可以在不使用Java的情況下享受JVM的優(yōu)勢(shì)。實(shí)際上,以其他語(yǔ)言使用JVM變得越來(lái)越重要,一致JVM中添加了一些新特性,其目的就是為了更好的支持這些語(yǔ)言。JVM的這些改進(jìn)已經(jīng)成為了Java 7和Java 8中的一些新特性。 這里還要提醒一點(diǎn),在不依賴特定平臺(tái)方面,提供“圖形用戶界面GUI”這個(gè)特性是非常困難的(GUI是指窗體、按鈕等這類的東西)。不過(guò)Java也能全平臺(tái)的支持。詳見1.6節(jié)。 |
|
|
來(lái)自: yy99k > 《java編程入門》