- 從零學Java設計模式
- (美)米羅斯拉夫·威格納
- 1879字
- 2024-12-03 17:59:39
1.2 編程:從符號到程序
我們說話的方式有很多種,能夠表達出的意思也遠超詞匯本身。人類能夠用名詞、動詞、形容詞等詞語準確表達某一時刻的感受或者某個動作。但與之相比,機器卻沒有辦法像人一樣理解一些比較復雜的指令與說法。
機器語言的詞匯有限,它所支持的表達方式是有嚴格定義的,而且定義得很具體,這些方式與人類的語言相比,顯得較為單純。機器語言的目標是準確地表達意圖,換句話說,機器語言就是為表達意圖而設計的。這與人類的語言不同,我們講話可能只是為了交流,而且不用像機器語言那樣把每個細節都說得很具體。
機器的意圖(或者說,你想讓機器去做的事情)可以用一條或一組具備明確定義的指令來表達。這意味著,機器是能夠理解指令的。然而,機器在執行指令時,必須能以某種形式拿到這樣的指令。每種機器通常都有它自己的一套指令。你可以從這套指令(或者說指令集)里面選擇一些傳給機器,讓它去執行,機器執行指令的流程如圖1.1所示。

圖1.1 CPU內部的指令循環簡圖(CPU是從內存獲取指令的,指令的執行結果也存儲到內存中)
現在我們來探討單個指令。指令,可以理解成發布給處理器的一條命令。處理器是計算機的核心,或者說,是計算機排列并執行指令時不可缺少的中心組件。一臺計算機可能只有一個處理器,也可能有多個處理器。究竟是哪種情況,要看計算機的設計。但無論如何,對于某一條具體的指令來說,總是會有一個處理器來處理。為了講得簡單一些,我們假設系統中只有一個用來執行程序的中央處理器(Central Processing Unit,CPU)。
CPU是一種用來執行指令的設備,而計算機程序實際上就是由一些指令組成的。每一種CPU都必須有它的指令集,圖1.1里的指令必須是這套指令集中的指令,只有這樣,CPU才知道怎么處理。
各種CPU所使用的指令在形式上可能區別很大,這沒有統一的標準。于是,我們會看到許多CPU平臺,這不一定是壞事,因為這樣可以促進CPU的發展。然而問題在于,無論哪一種形式的指令,人類解讀起來都不是特別容易。
我們剛才說了,計算機能夠執行指令集中的指令,而且理想情況下是連續不斷地執行。可以簡單地把這樣的一條指令流(flow of instruction)想象成內存中的一個隊列(queue),每次都有一條指令進來,同時也有一條指令離開。離開的這條指令就是排在隊列最前面的指令,它會被CPU獲取并得到處理。CPU相當于解釋器(interpreter),它反復從內存中獲取指令,如圖1.1所示。CPU負責解釋指令,可是內存中等著由它來解釋的這些指令來自何處?它們又是怎么匯聚成一條指令流的呢?
仔細想想,其實計算機指令在大多數情況下都是由編譯器(compiler)產生的。
什么是編譯器?編譯器可以看成一種針對特定CPU或特定平臺的程序,它把文本轉換成能夠在這種CPU或平臺上執行的操作。這里的文本就是我們自己編寫的源代碼,這些源代碼會由編譯器轉換為機器碼(machine code),以便在特定的平臺執行。這個流程如圖1.2所示。

圖1.2 源代碼經由編譯器處理變為能夠在特定的目標平臺上執行的機器碼
機器碼是一種能夠為計算機所理解的底層語言(low-level language),這種語言中的指令可以由CPU一條一條地處理(參見圖1.1)。編譯器就是要把你所寫的源代碼編譯為由機器碼所組成的程序,使得這個程序能夠在特定的平臺上運行。
我們在用Java語言編程的時候,沒有機器碼這個概念。
Java源代碼由Java編譯器編譯為字節碼(bytecode)。字節碼是運行在Java虛擬機(Java Virtual Machine,JVM)上的(參見圖1.3)。Java虛擬機是字節碼與目標平臺(或者說,目標CPU)之間的一個接口,它會把字節碼轉換成能夠在這種CPU上執行的指令。這樣的轉換由JIT編譯器(Just-In-Time compiler)來完成,它是JVM的一部分。JIT編譯器把字節碼轉換成能夠在具體的處理器上執行的指令。JVM本身能夠針對特定平臺來解釋字節碼,它的地位相當于圖1.2中的機器碼。此外,JVM還有其他一些特性,例如,內存管理與垃圾收集等,這些特性使得Java成為一個強大的開發平臺。前面說的種種特性,讓開發者只需要把自己寫的Java代碼編譯一次就好,編譯而成的字節碼能夠在Java虛擬機所支持的任何一種平臺上運行,這就是一次編寫,到處運行(Write Once,Run Anywhere,WORA)。

圖1.3 用Java語言寫成的源代碼,經由Java編譯器處理,變為不針對特定目標平臺的字節碼,Java虛擬機負責在特定的目標平臺上執行這些字節碼
根據剛才講的內容,Java應該是一種高級語言(high-level language),它經由Java虛擬機轉化為底層的(也就是低級的)機器碼。Java對計算機的細節做了大幅度的抽象,使得開發者能夠用簡單的代碼實現出復雜的功能,并確保這些功能可以在多種計算機上運作。
目前,我們討論了通用的解決方案。接下來,我們將會從內存的角度談談如何在保證代碼易于維護、易于擴展的前提下,降低它的內存占用量。最后我們將討論各種設計模式,讓這些模式幫助我們在日常工作中寫出清晰易懂而且更有意思的代碼。