Javac編譯過程

引入

Java的編譯器先將其編譯爲class文件,也就是字節碼,這一步稱爲Javac編譯;然後將字節碼交由jvm(java虛擬機)解釋執行,因而很多地方說“java是一種半編譯、半解釋執行”的語言。當然現在由於JIT的出現,這種說法有部分是錯誤的。接下來的兩篇博客,會簡略介紹一下Javac 編譯過程和JIT機制。

Javac編譯過程

Javac編譯器將.java文件編譯成爲.class文件的過程,這裏的Javac編譯器稱爲前端編譯器;相對應的還有後端編譯器,它在程序運行期間將字節碼轉變成機器碼。

Javac編譯(前端編譯)包括 詞法、語法分析填充符號表語義分析字節碼生成

詞法、語法分析

詞法分析是將源代碼的字符流轉變爲標記(Token)集合。單個字符是程序編寫過程中的的最小元素,而標記則是編譯過程的最小元素,關鍵字、變量名、字面量、運算符等都可以成爲標記。例如,下面這行代碼

int num = a + 6;

這行代碼包含了6個標記,分別是 int 、 num 、 = 、 a 、+ 、 6;

這裏的整型標誌int雖然由三個字符構成,但是它只是一個標記,不可拆分。

詞法分析的作用是將Java源文件的字符流轉變成對應的Token系列。而語法分析是將詞法分析生成的Token序列來構建更加結構化的抽象語法樹的過程。

抽象語法樹是一種用來描述程序代碼語法結構的樹形表示方式,語法樹的每一個節點都代表着程序代碼中的一個語法結構,例如包、類型、修飾符、運算符、接口、返回值甚至代碼註釋等都可以是一個語法結構。語法分析過程由com.sun.tools.javac.parser.Parser類實現,這個階段產出的抽象語法樹由com.sun.tools.javc.tree.JCTree類表示。

經過這個步驟之後,編譯器就基本不會再對源碼文件進行操作了,後續的操作都是建立在抽象語法樹上。

填充符號表

符號表是由一組符號地址符號信息構成的表格。在目標代碼生成階段,對符號名進行地址分配時,符號表是地址分配的依據。

可以把它想象成哈希表K-V值對,或者JavaScript中鍵值對的形式。

一個類除了類本身會定義一些符號變量如類名稱、變量名稱和方法名稱等,還有一些符號是引用其它類的,這些符號會調用其它類的方法或者變量等,還有一些類可能會繼承或者實現超類和接口等。這些符號都是在其他類中定義的,那麼就需要將這些類的符號也解析到符號表中。

記載的信息通常是標識符(identifier)的相關信息,如類型,作用域等。它通常會在語義分析(Semantic Analysis)階段運用到,如我們在語法分析(Syntax Analysis)階段是不會處理這樣的情況的:

int a;
a = "Hello,World!";

而這種情況,我們則可以在語義分析分析階段,利用Symbol Table進行處理,識別出類型的不匹配情況。

語義分析

語法樹能表示一個結構正確的源程序的抽象,但無法保證源程序是符合邏輯的。而語義分析的主要任務是讀結構上正確的源程序進行上下文有關性質的審查。
語義分析過程分爲標註檢查和數據及控制流分析兩個步驟:

  • 標註檢查步驟檢查的內容包括諸如變量使用前是否已被聲明、變量和賦值之間的數據類型是否匹配等。
  • 數據及控制流分析是對程序上下文邏輯更進一步的驗證,它可以檢查出諸如程序局部變量在使用前是否有賦值、方法的每條路徑是否都有返回值、是否所有的受查異常都被正確處理了等問題。

字節碼生成

字節碼生成階段不僅僅是把前面各個步驟所生成的信息轉化成字節碼寫到磁盤中,編譯器還進行了少量的代碼添加和轉換工作。 實例構造器()方法和類構造器()方法就是在這個階段添加到語法樹之中的。

字節碼生成結束後,.java文件就變成.class文件了,在執行Java程序時 ,字節碼由JVM逐條解釋執行。不過這是在JIT出現之前的情況了,下篇將介紹JIT。

筆者也是邊學邊寫,如有錯誤,請在評論中指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章