早期(編譯期)優化
前端編譯器(把*.java文件轉變成*.class文件):Sun的Javac、 Eclipse JDT中的增量式編譯器(ECJ)。
JIT編譯器(把字節碼轉變成機器碼):HotSpot VM的C1、 C2編譯器。
AOT編譯器(把*.java文件編譯成本地機器代碼):GNU Compiler for the Java(GCJ)、 Excelsior JET。
Javac編譯器
編譯過程大致分為三個:解析與填充符號表過程、插入式注解處理器的注解處理過程、分析與字節碼生成過程。
- 解析與填充符號表過程
- 1.詞法、 語法分析
- 詞法分析是將源代碼的字符流轉變為標記(Token)集合
-
語法分析是根據Token序列構造抽象語法樹的過程,抽象語法樹(Abstract Syntax Tree,AST)是一種用來描述程序代碼語法結構的樹形表示方式,語法樹的每一個節點都代表著程序代碼中的一個語法結構(Construct)
圖1 Javac編譯過程
- 2.填充符號表
- 符號表(Symbol Table)是由一組符號地址和符號信息構成的表格
- 1.詞法、 語法分析
- 注解處理器
- 如果插入式注解處理器在處理注解期間對語法樹進行了修改,編譯器將回到解析及填充符號表的過程重新處理,直到所有插入式注解處理器都沒有再對語法樹進行修改為止,如圖1的回環過程(Round)。
- 語義分析與字節碼生成
- 語義分析的主要任務是對結構上正確的源程序進行上下文有關性質的審查,如進行類型檢查。
- 語義分析過程分為標注檢查以及數據及控制流分析
- 1.標注檢查
- 檢查的內容包括諸如變量使用前是否已被聲明、 變量與賦值之間的數據類型是否能夠匹配等
- 2.數據及控制流分析
- 對程序上下文邏輯更進一步的驗證,它可以檢查出諸如程序局部變量在使用前是否有賦值、 方法的每條路徑是否都有返回值、 是否所有的受查異常都被正確處理了等問題。
- 1.標注檢查
- 局部變量與字段(實例變量、 類變量)是有區別的,它在常量池中沒有
CONSTANT_Fieldref_info的符號引用,自然就沒有訪問標志(Access_Flags)的信息,甚至可能連名稱都不會保留下來(取決于編譯時的選項),自然在Class文件中不可能知道一個局部變量是不是聲明為final- 3.解語法糖
- 語法糖指指在計算機語言中添加的某種語法,這種語法對語言的功能并沒有影響,但是更方便程序員使用。
- 虛擬機運行時不支持泛型、變長參數等語法,它們在編譯階段還原回簡單的基礎語法結構,這個過程稱為解語法糖。
- 4.字節碼生成
- 字節碼生成階段不僅僅是把前面各個步驟所生成的信息(語法樹、 符號表)轉化成字節碼寫到磁盤中,編譯器還進行了少量的代碼添加和轉換工作。
- 實例構造器<init>()方法和類構造器<clinit>()方法就是在這個階段添加到語法樹之中的
- 3.解語法糖
Java語法糖
泛型與類型擦除
泛型技術實際上是Java語言的一顆語法糖,Java語言中的泛型實現方法稱為類型擦除,基于這種方法實現的泛型稱為偽泛型。