學習java以來,都是以語法,類庫入手,最基本的也是最基礎的java編譯過程往往被我遺忘,先解釋一下學習java第一課時,都聽到過的一句話,“java是半解釋語言”。什麼是半解釋語言。
Java的編譯過程
Java程式從原始檔建立到程式執行要經過兩大步驟
1、原始檔由編譯器編譯成位元組碼(ByteCode)
2、位元組碼由java虛擬機器解釋執行。因為java程式既要編譯同時也要經過JVM的解釋執行,所以說Java被稱為半解釋語言( "semi-interpreted" language)。
一個栗子
下面我們通過一個簡單的 OneTest.java,來看一下一個java檔案從編譯到執行的歷程。
Public class OneTest{ public static void main(String[] args){ Person one = new Person(); one.say(); } }
Public class Person{ private String name; public void say(){ System.out.println("I `m a Person"); } }
這裡是兩個java檔案,分別是OneTest.java,Person.java
第一步
首先是編譯階段,由JVM編譯器,將OneTest.java檔案進行編譯,得到位元組碼檔案(OneTest.class),這裡我們發現,OneTest.java中依賴了Person物件,也就是需要Person.java檔案,編譯器便會檢索Persion.java是否被編譯(是否存在Person.class),若不存在,則先編譯Person.java,java編譯一個類時,如果這個類所依賴的類還沒有被編譯,編譯器會自動的先編譯這個所依賴的類,然後引用。
1、如果java編譯器在指定的目錄下找不到該類所依賴的類的 .class檔案或者 .java原始檔,就會報 “Cant found sysbol”的異常錯誤。
2、編譯後的位元組碼檔案格式主要分為兩部分:常量池和方法位元組碼。
常量池記錄的是程式碼出現過的常量、類名、成員變數(Person.java中的類Person名、name成員變數)等以及符號引用(類引用、方法引用(OneTest.java中的person.say),成員變數引用等);方法位元組碼中放的是各個方法的位元組碼。
第二步
然後進行解釋執行階段,這裡執行階段分為兩步:類的載入和類的執行
JVM主要在程式第一次主動使用類的時候,才會去載入該類。也就是說,JVM並不是在一開始就把一個程式就所有的類都載入到記憶體中,而是到不得不用的時候才把它載入進來,而且只載入一次。
1、OneTest類的載入:在類路徑下找到編譯好的 java 程式中;得到 OneTest.class 位元組碼檔案後,系統就會啟動一個 JVM 程式,JVM程式從classpath路徑下找到一個名為OneTest.class的二進位制檔案,將OneTest.class檔案中的類資訊載入到執行時資料區的方法區中,這一過程叫做類的載入。(只有類資訊在方法區中,才能建立物件,使用類中的成員變數)關於類的載入器
2、執行OneTest.java中的main方法:main函式的第一條命令是Persion person = new Person();就是讓JVM建立一個Person物件,但是這時候方法區中沒有Person類的資訊,所以JVM馬上載入Person類,把Person類的型別資訊放到方法區中。
3、載入完Person類之後,Java虛擬機器做的第一件事情就是在堆區中為一個新的Person例項分配記憶體, 然後呼叫建構函式初始化Person例項,這個Person例項持有著指向方法區的Person類的型別資訊(其中包含有方法表,java動態繫結的底層實現)的引用
4、當使用person.say()的時候,JVM根據person引用找到Person物件,然後根據Person物件持有的引用定位到方法區中Person類的型別資訊的方法表,獲得say()函式的位元組碼的地址。
5、執行say方法。