一、類加載的詳細過程
1、加載:将二進制資料寫入記憶體,并在堆區建立能夠映射方法區中相應類的方法的Class對象。
加載的方式:
(1)本地系統加載(注意加載的起始搜尋路徑)
(2)網絡下載下傳檔案中加載
(3)從zip,jar壓縮檔案等歸檔檔案中加載
(4)從專有資料庫中提取.class檔案
(5)将java源檔案動态編譯為.class檔案
2、連接配接:就是将已經讀入到記憶體的類的二進制資料合并到虛拟機的運作時環境中去。包括驗證、準備、解析三個步驟。
(1)驗證:類檔案的結構檢查、語義檢查、位元組碼驗證、二進制相容性的驗證。
(2)準備:為靜态變量配置設定記憶體并置系統預設值。
(3)解析:将符号引用轉換為直接引用。
3、初始化:為靜态變量賦予初始值。初始化類僅在主動使用類的情況下執行。
主動使用主要包括:建立類的執行個體、通路類的靜态成員、反射、初始化一個類的子類、啟動類。
二、類加載器的層次結構及其工作原理
1、類加載器的作用
類加載器負責讀取java位元組碼檔案,并将其轉換成java.lang.class類的一個執行個體。每個這樣的執行個體都代表一個java類。通過此執行個體的newInstance()方法就可以建立一個該執行個體的對象。在程式中,可以通過classname.class的方式引用class的一個classname執行個體。
需要注意的是,java中的所有類都是class類的執行個體。
2、類加載器的分類
(1)引導類加載器:加載java核心庫,用原生代碼實作。
(2)擴充類加載器:加載java擴充庫。Java虛拟機的實作會提供一個擴充庫的目錄,擴充類加載器會自動從此目錄中查找并加載java類。
(3)系統類加載器:根據java應用定義的類路徑(classpath)查找并加載java類。其父類為擴充類加載器。
(4)自定義加載器:由使用者定義并且繼承自ClassLoader類的加載器,其父類加載器一般為系統類加載器。
3、類加載器的父委托機制
(1)類加載的過程:當一個類加載器啟動加載一個類時,首先将任務交由父加載器處理,而父對象按同樣的方式進行工作。如果父加載器已經或能夠完成就傳回此類型,否則由子加載器處理。
(2)父子關系的了解:父子加載器并不一定是繼承關系,而是包含關系。任一加載器都必須有且唯一的父加載器,所有的加載器都在樹形結構中有自己的位置。引導類加載器的名字為null。
(3)定義與初始類加載器概念:成功加載類的為定義加載器,從定義加載器開始到發起加載請求的加載器之間都是初始加載器。這個概念主要辨別類加載器的加載記錄。
(4)代理模式的作用:保護核心類庫和對類的通路限制。
4、java類的加載方式
(1)隐式加載:當用需要并且用new關鍵字執行個體化一個對象時,系統将調用目前線程的類加載器加載一個類。
(2)顯式加載:我們可以指定一個類加載器去加載一個類。有兩種方式支援這麼做。一種是用java.lang.class中的forName()方法,另一種是java.lang.classloader中的loadclass()方法。這兩種方法都加載指定的類并且傳回class類的一個執行個體。
三、自定義類加載器
1、類加載器的工作流程圖
(1)檢視自己是否已經加載過該類,如果有,則傳回該類;如果沒有進入下一步。
(2)如果有父加載器,讓父加載器從第一步開始執行(遞歸)。如果沒有,則自行加載。
(3)如果不能加載,抛出ClassNotFoundException異常。如果不是初始發動加載請求的加載器,異常将被子加載器捕捉。
(4)如果子加載器發現ClassNotFoundException,則自行加載。
(5)最終,能加載,則進入下一步,否則抛出ClassNotFoundException異常。
(6)檢查resolve是否為真,如果為真,則進行連接配接操作。
(7)傳回類。
2、加載的實作過程說明
(1)加載的入口函數為loadClass,已由系統實作。對于(1)(2)(3)(5)(6)(7)等正常步驟,也由系統給出。我們需要做的就是自行加載的子產品。
(2)自行加載子產品的接口為findclass,主要完成将二進制資料載入記憶體并調用defineclass函數映射成class的執行個體的任務。
(3)findclass必須抛出ClassNotFoundException異常,以便在遞歸序列中被接過任務的子加載器捕捉。
(4)findclass不能由其他其他異常中斷,否則遞歸序列無法繼續到最後。
(5)必須重載classloader的兩個構造函數,以構成加載器父委托機制。