1、java類的編譯流程java
這裏主要講的是從java文件到class文件數據庫
下圖是java類編譯的詳細步驟:安全
1.詞法分析:將java源代碼的字符流轉變爲標記(Token)的集合,Token是編譯過程當中的最小元素,關鍵字、變量名、字面量、運算符均可以成爲標記。如int a = b + 2 這句代碼包含了6個標記,分別是int 、 a、=、b、+、2。網絡
2.語法分析:將利用詞法分析後的Token序列構造抽象語法樹的過程。抽象語法樹是一種用來描述程序語法結構的樹的表現方式,語法樹的每個節點都表明程序代碼中的一個語法結構,例如:包、類型、修飾符、運算符、接口、返回信息、代碼註釋等都是語法結構。數據結構
3.填充符號表:符號表是由一組符號地址和符號信息構成的表格,表中登記的信息在編譯的不一樣階段都要用到。在語義分析中,符號表所登記的內容將用於語義檢查和產生中間代碼。在目標代碼生成階段,當對符號名進行地址分配時,符號表是地址分配的依據。插件
4.註解處理器:JDK1.5加入了對註解的支持,須要在編譯期間對註解進行處理。咱們能夠將註解處理器看做一組插件,能夠修改抽象語法樹中的任意元素。在處理註解的過程當中,每次修改抽象語法樹後,編譯器將回到解析及填充符號表的過程從新處理。代理
5.語義分析:在語法分析後,編譯器得到了程序代碼的抽象語法樹表示,語法樹可以表示一個結構正確的源程序的抽象,但沒法保證源程序是符合邏輯的。語義分析的主要任務就是對結構上正確的源程序進行上下文有關的性質審查。指針
5.1標註檢查:如變量使用前是否已經被申明,變量賦值類型是否匹配。還有一個重要的動做叫常量摺疊,如int i = 1+2; 在常量數上會直接標記爲3。對象
5.2數據及控制流分析:對程序上下文的邏輯進一步驗證,它能夠檢查出如局部變量在使用前是否賦值、方法的每條路徑是否有返回、是否全部的受檢異常都被正確處理了等問題。blog
5.3解語法糖:語法糖是在計算機語言中添加某種語法,用來提升程序的可讀性,減小代碼的出錯機會。如泛型、變長參數、自動拆箱和裝箱等。
6.字節碼生成:字節碼生成階段不只僅把前面各個步驟生成的信息(語法樹、符號表)轉化爲字節碼寫到磁盤中,編寫器還進行了少許的代碼添加和轉換工做。最後輸出字節碼
2、虛擬機的類加載機制
1.虛擬機把描述類的class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終造成能夠被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。
2.類加載過程:
分別是加載、驗證、準備、解析、初始化。其中驗證、準備和解析統稱爲鏈接;這些步驟中加載、驗證、準備、初始化的順序是肯定的,而解析階段則可能在初始化以後。
2.一、加載:在加載階段,虛擬機只須要完成下面三件事
2.1.一、經過類的全限定名來獲取定義此類的二進制流。
java虛擬機並無規定從哪加載二進制流,能夠是壓縮包中,可從網絡中,可用從數據庫中,也能夠是計算機運算生成(動態代理產生的代理類)等。
2.1.二、將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構。
虛擬機外部的二進制字節流就按照虛擬機所需的格式存儲在方法區中,方法區中的數據存儲格式由虛擬機實現自定義。
2.1.三、在內存中生成一個表明這個類的java.lang.Class對象,做爲方法區這個類的各類數據的訪問入口。
這裏並無規定存在java堆中,在HotSpot中它是存儲在方法區裏面。
2.二、驗證:驗證是鏈接階段的第一步,這一階段的目的是爲了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,而且不會危害到自身的安全
驗證大體會分爲4個階段的校驗動做:
2.2.一、文件格式驗證:主要驗證字節流是否符合Class文件的規範,而且可以被當前版本的虛擬機處理等。該階段的驗證主要是保證輸入的本身流可以正確的解析而且存儲於方法區以內。只有經過了驗證後,字節流纔會進入內存的方法區中進行存儲。
2.2.二、元數據驗證:對字節碼描述的信息進行語義分析,以保證描述的信息符合java語言規範的要求。
2.2.三、字節碼驗證:主要的目的是經過對數據流和控制流分析,肯定程序語義是合法的、符合邏輯的。確保被驗證的類不會危害虛擬機的安全。
2.2.四、符號引用驗證:這個階段發生在虛擬機將符號引用轉化爲直接引用的時候,這個轉化動做將在鏈接的第三階段-----解析中發生。符號引用驗證能夠看做對類自身之外的信息進行匹配校驗。
2.三、準備:正式爲類變量(靜態變量)分配初始內存並設置初始值(並非代碼的初始賦值)的階段,這些變量所使用的內存都將在方法區中進行分配。若是是常量則直接分配爲常量值。
2.四、解析:將虛擬機中常量池內的符號引用替換爲直接引用的過程。
2.4.一、符號引用:符號引用以一組符號來描述所引用的目標,符號能夠是任何形式的字面量,只要使用時可以無歧義定位到目標便可。
2.4.二、直接引用:直接引用能夠是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。
2.五、初始化:初始化是類加載的最後一步,前面的類加載的過程當中,除了在加載階段用戶應用程序能夠經過自定義類加載器參與外,其他動做徹底由虛擬機主導和控制。到了初始化階段,才真正開始執行類中定義的java程序代碼。
3、雙親委派模型
從java虛擬機的角度講,只存在兩種類加載器:一種是啓動加載器(Bootstrap ClassLoader),這個加載器使用C++語言實現,是虛擬機自身的一部分;另外的加載器都是由java語言實現,獨立於虛擬機外部,而且都繼承自抽象類java.lang.ClassLoader。
啓動類加載器(Bootstrap ClassLoader):負責加載虛擬機啓動所須要的類庫。它只能加載本身可以識別的類。
擴展類加載器(Extendtion ClassLoader):它負責加載<JAVA_HOME>\lib\ext目錄中的或者被java.ext.dirs系統變量所指定的路徑中的全部類庫,開發者可使用擴展類加載器。
應用程序類加載器(Application ClassLoader):負責加載CLassPath上所指定的類庫,若是應用程序沒有自定義過本身的類加載器,通常狀況下這就是程序的默認類加載器。
自定義類加載器(User ClassLoader):本身定義的類加載器
雙親委派模型要求除了頂層的啓動類加載器外,其他的類加載器都應該有本身的父類加載器。而且類加載器之間的父子關係不是經過繼承來實現的,而是經過組合關係來複用父類加載器的代碼。
雙親委派模型的工做過程是若是一個類加載器收到類加載的請求,它首先不會本身去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,所以全部的加載請求最終都會委派到啓動類加載器中。只有父類加載器反饋本身沒法加載這個類時,子類加載器纔會嘗試本身去加載。