虛擬機把描述類的數據從 Class 文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終造成能夠被虛擬機直接使用的 Java 類型,這就是虛擬機的類加載機制。java
加載 -> 鏈接(驗證、準備、解析) -> 初始化 -> 使用 -> 卸載程序員
加載、驗證、準備、初始化和卸載這 5 個階段的順序是肯定的,類的加載過程必須按這種順序循序漸進地開始。解析階段則不必定,它在某些狀況能夠在初始化以後再開始,這是爲了支持 Java 語言的運行時綁定(也稱動態綁定或晚期綁定)。安全
這些階段一般是互相交叉地混合式進行,一般會在一個階段執行的過程當中調用、激活另一個階段。數據結構
「加載」是「類加載」過程的一個階段,在加載階段,虛擬機須要完成 3 件事:spa
這一階段的目的是爲了確保 Class 文件的字節流中包含的信息符合當前虛擬機的要求,而且不會危害虛擬機自身的安全。驗證階段大體包含 4 個階段的檢驗動做。設計
驗證字節流是否符合 Class 文件格式的規範,而且能被當前版本的虛擬機處理。指針
驗證內容:對象
主要目的是保證輸入的字節流能正確解析並存儲於方法區內,格式上符合描述一個 Java 類型信息的要求。繼承
該階段的驗證是基於字節流進行的,只有驗證經過了,字節流纔會進入內存的方法區中進行存儲。因此後面 3 個驗證階段都是基於方法區的存儲結構進行的。接口
對字節碼描述的信息進行語義分析,以保證其描述的信息符合 Java 語言規範的要求。
驗證內容:
主要目的是對類的元數據信息進行語義校驗,保證不存在不符合 Java 語言規範的元數據信息。
對類的方法體進行檢驗分析,保證類的方法在運行時不會作出危害虛擬機安全的事件。
驗證內容:
主要目的是經過數據流和控制流分析,肯定程序語義是合法的、符合邏輯的。
對類自身之外(常量池中的各類符合引用)的信息進行匹配性校驗。這一階段發生在虛擬機將符號引用轉化爲直接引用時。
驗證內容:
主要目的是確保解析動做能正常執行。
準備階段是爲類變量分配內存並設置初始值的階段。
有兩點須要強調一下:
解析階段是虛擬機將常量池內的符號引用替換爲直接引用的過程。
解析動做主要針對類或接口、字段、類方法、接口方法、方法類型、方法句柄和調用點限定符 7 類符號引用進行,分別對應常量池的 CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info、CONSTANT_MethodType_info、CONSTANT_MethodHandle_info 和 CONSTANT_InvokeDynamic_info 7 種常量類型。
初始化階段是根據程序員的主觀計劃去初始化類變量和其餘資源的階段。或者從另外一個角度表達,初始化階段是執行類構造器 clinit() 方法的過程。
到了初始化階段,才真正開始執行類中定義的 Java 程序代碼(或者說字節碼)。
虛擬機設計團隊把類加載階段中的「經過類的全限定名獲取定義此類的二進制字節流」這個動做放到 Java 虛擬機外部去實現,以便讓應用程序本身決定如何去獲取所需的類。實現這個動做的代碼模塊稱爲「類加載器」。
對於任意一個類,都須要由加載它的類加載器(每個類加載器都有一個獨立的類名稱空間)和這個類自己,一同確立其在 Java 虛擬機中的惟一性。
換句話說,比較兩個類是否「相等」,只有在這兩個類是由同一個類加載器加載的前提下才有意義。
從 Java 虛擬機角度講,只存在兩種不一樣的類加載器:
從 Java 開發人員角度講,可分爲三種類加載器:
若是一個類加載器收到類加載的請求,它會先把這個請求委派給父加載器去完成,而不會本身去嘗試加載這個類。只有父加載器沒法完成這個加載請求時,子加載器纔會嘗試本身去加載。