一般,一個java文件會經過編譯器編譯成字節碼文件.class,再又java虛擬機JVM翻譯成計算機可執行的文件。java
咱們所知道的java語言有它本身的語法規範,一樣的JVM也有它的語法規範,如何讓java的語法規則去適應語法解析規則,這就是javac的做用,簡而言之,javac的做用就是將java源代碼轉化成class字節碼文件。bash
將源碼轉化爲Token流jvm
讀取源代碼,從源文件的一個字符開始,按照java語法規範依次找出package,import,類定義,屬性,方法定義等,最後構建出一個抽象語法樹函數
package compile;
/**
* 詞法解析器
*/
public class Cifa{
int a;
int c = a + 1;
}
複製代碼
轉化爲Token流: 源碼分析
Javac在進行此法分析時會由JavacParser根據Java語言規範來控制什麼順序,地方會出現什麼Token,例如package就只能在文件的最開頭出現ui
對於關鍵字,主要由關鍵字的語法規則,例如package就是若一個字符串package是連續的,那麼他就是關鍵字this
對於自定義變量名稱,自定義名稱之間用空格隔開,每一個語法表達式用分號結束spa
int a = 1 + 2;翻譯
從package開始code
.....
int 就是經過語法關鍵字斷定的TOKEN:INT
int a之間經過空格隔開
a 就是自定義的變量被斷定爲TOKEN:IDENTIFIER
a =之間經過空格隔開(這時有的小夥伴就會說了,int a=b+c;這句話也不報錯啊,對的,大多數時候,這種不用空格分開確實可以編譯,這是由於java指出聲明變量的時候必須以字母、下劃線或者美圓符開頭,當JavacParser讀完a去讀=的時候就直到這個=不屬於變量了)將=斷定爲TOKEN:EQ
1被斷定爲TOKEN:INTLITERAL
.....
將;識別爲TOKEN:SEMI
.....
最後讀取到類結束,也就是}被斷定爲TOKEN:RBRACE
剛纔,詞法解析器已經將Java源文件解析成了Token流。
如今,語法解析器就要將Token流組建成更加結構化的語法樹。也就是將這些Token流中的單詞裝成一句話,完整的語句。
將進行詞法分析後造成的Token流中的一個個Token組成一句句話,檢查這一句句話是否是符合Java語言規範。
Tree tag:每一個語法節點都會以整數的形式表示,下一個節點在上一個節點上加1;
複製代碼
pos:也是一個整數,它存儲的是這個語法節點在源代碼中的起始位置,一個文件的位置是0,而-1表示不存在
複製代碼
type:它表明的是這個節點是什麼java類型,如int,float,仍是string等
複製代碼
package compile;
/**
* 語法
*/
public class Yufa {
int a;
private int c = a + 1;
//getter
public int getC() {
return c;
}
//setter
public void setC(int c) {
this.c = c;
}
}
複製代碼
注1:若類中有import關鍵字則途中還有import的語法節點
注2:全部語法節點的生成都是在TreeMaker類中完成的
將語法樹轉化爲註解語法樹,即在這顆語法樹上作一些處理
給類添加默認構造函數(由com.sun.tools.javac.comp.Enter類完成)
處理註解(由com.sun.tools.javac.processing.JavacProcessingEnvironment類完成)
檢查語義的合法性並進行邏輯判斷(由com.sun.tools.javac.comp.Attr完成)
數據流分析(由com.sun.tools.javac.comp.Flow類完成)
對語法樹進行語義分析(由com.sun.tools.javac.comp.Flow執行)
最終,生成了註解語法樹
變量自動轉化
public class Yuyi{
public static void main(String agrs[]){
Integer i = 1;
Long l = i + 2L;
System.out.println(l);
}
}
//通過自動轉換後
public class Yuyi{
public Yuyi(){
super();
}
public static void main(String agrs[]){
Integer i = Integer.valueOf(1);
Long l = Long.valueOf(i.intValue() + 2L);
System.out.println(l);
}
}
複製代碼
解除語法糖
public class Yuyi{
public static void main(String agrs[]){
int[] array = {1,2,3};
for (int i : array){
System.out.println(i);
}
}
}
//解除語法糖後
public class Yuyi{
public Yuyi(){
super();
}
public static void main(String agrs[]){
int[] arrays = {1,2,3};
for (int[] arr$ = array,len$=arr$.length,i$=0; i$<len$; ++i$){
int i = arr$[i$];
{
System.out.println(i);
}
}
}
}
複製代碼
內部類解析
public class Yuyi{
public static void main(String agrs[]){
Inner inner = new Inner();
inner.print();
}
class Inner{
public void print(){
System.out.println("Yuyi$Inner.print");
}
}
}
//轉化後的代碼以下
public class Yuyi{
public Yuyi(){
super();
}
public static void main(String agrs[]){
Yuyi$Inner inner = new Yuyi$Inner(this);
inner.print();
}
{
}
}
class Yuyi$Inner{
/*synthetic*/ final Yuyi this$0;
Yuyi$Inner(/*synthetic*/final Yuyi this$0){
this.this$0 = this$0;
super();
}
public void print(){
System.out.println("Yuyi$Inner.print");
}
}
複製代碼
生成語法樹後,接下來Javac會調用com.sun.tools.javac.jvm.Gen類遍歷語法樹,生成Java字節碼
參考書籍:《深刻分析Java Web》