HelloWorld是每個Java程式員都知道的程式。它很簡單,但是簡單的開始可以引導你去深入了解更複雜的東西。這篇文章将探究從這個HelloWorld這個簡單程式中可以學到的東西。如果你對HelloWorld有獨到的了解,歡迎留下你的評論。
HelloWorld.java
?
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
1、為什麼一切都是從類開始?
Java程式是從類開始建構的, 每個方法和字段都必須在類裡面。這是由于Java面向對象的特性: 一切都是對象,它是類的一個執行個體。面向對象程式設計語言相比函數式程式設計語言有許多的優勢,比如更好的子產品化、可擴充性等等。
2、為什麼總有一個“main方法”?
main方法是程式的入口,并且是靜态方法。static關鍵字意味着這個方法是類的一部分,而不是執行個體對象的一部分。為什麼會這樣呢? 為什麼我們不用一個非靜态的方法作為程式的入口呢?
如果一個方法不是靜态的,那麼對象需要先被建立好以後才能使用這個方法。因為這個方法必須要在一個對象上調用。對于一個入口來說,這是不現實的。是以,程式的入口方法是靜态的。
參數 “String[] args”表明可以将一個字元串數組傳遞給程式來幫助程式初始化。
3、HelloWorld程式的位元組碼
為了執行這個程式,Java檔案首先被編譯成Java位元組碼存儲到.class檔案中。那麼位元組碼看起來是什麼樣的呢?位元組碼本身是不可讀的,如果我們使用一個二進制編輯器打開,它看起來就像下面那樣:
在上面的位元組碼中,我們可以看到很多的操作碼(比如CA、4C等等),它們中的每一個都有一個對應的助記碼(比如下面例子中的aload_0)。操作碼是不可讀的,但是可以使用javap來檢視.class檔案的助記形式。
對于類中的每個方法執行“javap -c”可以輸出反彙編代碼。反彙編代碼即組成Java位元組碼的指令。
?
1 | |
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
上面的代碼包含兩個方法: 一個是編譯器推斷出來的預設的構造器;另外一個是main方法。
接下來,每個方法都有一系列的指令。比如aload_0、invokespecial #1等等。可以在Java位元組碼指令集中查到每個指令的功能,例如aload_0用來從局部變量0中加載一個引用到堆棧,getstatic用來擷取類的一個靜态字段值。可以注意到,getstatic指令之後的“#2″指向的是運作期常量池。常量池是JVM運作時資料區之一。我們可以通過“javap -verbose”指令來檢視常量池。
另外, 每個指令從一個數字開始,比如0、1、4等等。在.class檔案中,每個方法都有一個對應的位元組碼數組。這些數字對應于存儲每個操作碼及其參數的數組的下标。每個操作碼都是1個位元組長度,并且指令可以有0個或多個參數。這就是為什麼這些數字不是連續的原因。
現在,我們使用“javap -verbose”這個指令來進一步觀察這個類。
?
1 | |
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | |
引用JVM規範中的描述:運作期常量池提供的功能類似傳統程式設計語言的符号表所起作用, 盡管它比傳統的符号表包含的内容更廣範。
“invokespecial #1″指令中的“#1″指向常量池中的#1常量。這個常量是 “Method #6.#15;”。通過這個數字,我們可以遞歸地得到最終的常量。
LineNumberTable為調試器提供了用來訓示Java源代碼與位元組碼指令之間的對應資訊。例如,Java源代碼中的第9行對應于main方法中的位元組碼0,并且第10行對應于位元組碼8。
如果想要了解更多關于位元組碼的内容,可以建立一個更加複雜的類進行編譯和檢視,HelloWorld真的隻是一個開始。
4、HelloWorld在JVM中是如何執行的?
現在的問題是JVM是怎樣加載這個類并調用main方法?
在main方法執行之前, JVM需要加載、連結以及初始化這個類。
1. 加載将類/接口的二進制形式裝入JVM中。
2. 連結将二進制類型的資料融入到JVM的運作時。連結由3個步驟組成:驗證、準備、以及解析(可選)。驗證確定類、接口在結構上是正确的;準備涉及到為類、接口配置設定所需要的記憶體;解析是解析符号引用。
3. 最後,初始化為類變量配置設定正确的初始值。
加載工作是由Java類加載器來完成的。當JVM啟動時,會使用下面三個類加載器:
- Bootstrap類加載器:加載位于/jre/lib目錄下的核心Java類庫。它是JVM核心的一部分,并且使用本地代碼編寫。
- 擴充類加載器:加載擴充目錄中的代碼(比如/jar/lib/ext)。
- 系統類加載器:加載在CLASSPATH上的代碼。
是以,HelloWorld類是由系統加載器加載的。當main方法執行時,它會觸發加載其它依賴的類,進行連結和初始化。前提是它們已經存在。
最後,main()幀被壓入JVM堆棧,并且程式計數器(PC)也進行了相應的設定。然後,PC訓示将println()幀壓入JVM堆棧棧頂。當main()方法執行完畢會被彈出堆棧,至此執行過程就結束了。
參考文檔
- 加載
- 類加載機制
- 類加載器
原文連結: programcreek 翻譯: ImportNew.com - 黃飛飛
http://www.admin10000.com/document/3828.html