Javac編譯器是把 *.java 文件轉換爲 *.class 文件,是一個前端編譯器;對應着有一種把字節碼轉變爲機器碼的編譯器,稱爲JIT編譯器(Just In Time Compiler),好比 HotSpot VM 的C一、C2編譯器;把 *.java 文件編譯成機器碼的編譯器稱爲靜態提早編譯器;前端
Javac編譯器編譯的過程能夠爲3個過程:java
一、解析與填充符號表:程序員
這個過程又能夠細分爲詞法分析、語法分析和填充符號表;數組
詞法分析:詞法分析是將源代碼的字符流轉變爲標記(Token)集合,單個字符是程序編寫過程的最小元素,而標記則是編譯過程的最小元素,關鍵字、變量名、字面量、運算符均可以成爲標記。緩存
語法分析:語法分析是根據Token序列構造抽象語法樹的過程,抽象語法樹(Abstract Syntax Tree)是一種用來描述程序代碼語法結構的樹形表示方式,語法樹的每個節點都表明着程序代碼中的一個語結構。插件
符號表(Symbol Tree):符號表是一組符號地址和符號信息構造的表格,符號表登記的信息在編譯的不一樣階段都要用到。blog
二、插入式註解處理器的註解處理:插入式註解器至關於編譯器的插件,咱們能夠經過註解處理器讀取、修改、添加抽象語法樹中的任意元素。若是對抽象語法樹進行了修改,編譯器將會從新回到解析及填充符號表的過程從新處理,直到全部插入式註解處理器都沒有再對語法樹進行修改成止。接口
三、語義分析與字節碼生成過程:語法分析的主要任務是對結構上正確的源程序進行上下文有關性質的審覈,保證源代碼程序符合邏輯。編譯器
語義分析又能夠細分爲 標註檢查和數據及控制流分析:it
標註檢查:標註檢查檢查的內容包括變量使用前是否被聲明、變量與賦值之間的數據類型是否可以匹配,常量摺疊(好比 int a = 1 * 2; 會處理爲 int a = 3;)等等;
數據及控制流檢查:檢查內容有程序局部變量在使用前是否有賦值、方法的每一條路徑是否都有返回值,是否全部的受查異常都被正常的處理 等等;
語法糖:指在計算機語言中添加某種語法,這種語法對語言的功能並無影響,可是方便程序員使用;
字節碼生成:字節碼生成是把前面各個步驟所生成的信息(語法樹、符號表)轉化成字節碼寫到磁盤的過程,在這個過程當中還進行了很多代碼添加和轉換的工做,好比生成實例構造器和類構造器;
Java 語法糖
一、泛型與類型擦除:
泛型是JDK 1.5 的一項新增特性,它的本質是參數化類型的應用,也就是說所操做的數據類型被指定爲一個參數。這種參數類型能夠用在類、接口和方法的建立中,分別稱爲泛型類、泛型接口和泛型方法。
Java的泛型是一種僞泛型,它只存在於程序的源代碼中,在編譯後的字節碼文件中,就已經替換爲原來的原生類型。
二、自動拆箱、裝箱和遍歷循環:
自動裝箱、自動拆箱反編譯後對應包裝類的包裝、還原方法;
遍歷循環 反編譯後對應 迭代器實現;
變長參數 反編譯後 變成了一個數組類型的參數;
// 如下是源代碼,包含了泛型,自動裝箱,自動拆箱、遍歷循環、變長參數共5種語法糖 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); int sum = 0; for (int i : list) { sum += i; } System.out.println(sum); //反編譯後的源代碼 List list = Arrays.asList(new Integer[] { null, null, null, null, (new Integer[5][3] = (new Integer[5][2] = (new Integer[5][1] = (new Integer[5][0] = Integer.valueOf(1)).valueOf(2)).valueOf(3)).valueOf(4)).valueOf(5) }); int i = 0; for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { int j = ((Integer)iterator.next()).intValue(); i += j; } System.out.println(i);
三、自動裝箱的陷阱:
// 源代碼 Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; System.out.println(c == d); System.out.println(e == f); System.out.println(c == (a + b)); System.out.println(c.equals(a + b)); System.out.println(g == (a + b)); System.out.println(g.equals(a + b)); // 反編譯後的代碼 Integer integer1 = Integer.valueOf(1); Integer integer2 = Integer.valueOf(2); Integer integer3 = Integer.valueOf(3); Integer integer4 = Integer.valueOf(3); Integer integer5 = Integer.valueOf(321); Integer integer6 = Integer.valueOf(321); Long l = Long.valueOf(3L); System.out.println((integer3 == integer4)); System.out.println((integer5 == integer6)); System.out.println((integer3.intValue() == integer1.intValue() + integer2.intValue())); System.out.println(integer3.equals(Integer.valueOf(integer1.intValue() + integer2.intValue()))); System.out.println((l.longValue() == (integer1.intValue() + integer2.intValue()))); System.out.println(l.equals(Integer.valueOf(integer1.intValue() + integer2.intValue()))); // 運行結果 true false true true true false //說明 1. 包裝類的 「==」 運算在遇到算術運算符會自動拆箱 2. 包裝類的 equals 方法先會判斷比較的類型是否 instanceof 包裝類 3. 當Integer,Long包裝類在自動裝箱時若是值在 -128 ~ 127 之間時會共享緩存值
四、條件編譯
javac編譯器會把條件分支中永遠不會執行的分支消除掉。