JVM 類加載機制分為五個部分:加載,驗證,準備,解析,初始化,下面我們就分別來看一下這五個過程。
加載
加載是類加載過程中的一個階段,這個階段會在內存中生成一個代表這個類的
java.lang.class 對象,作為方區這個類的各種數據的入口,注意這里不一定非得要
從一個class文件獲取,這里既可以從zip 包中讀出(比如從 jar 包),也可以由其它文件
生成(比如將JSP文件 轉換成對應的Class類)
驗證
這一階段的主要目的是為保證Class文件的字節流包含的信息是否符合當前虛擬機的要求
,并且不會危害虛擬自身的安全
準備
準備階段是正式為類變量分配內存并設置類變量的初始值階段,既在方法區中分配這些變量
所使用的內存空間,注意這里所說的初始值概念,比如一個類變量定義為:
public static int v=80;
準備階段后初始值 為0 而不是80
解析
解析階段將類中的符號引用轉換為直接引用,即將類、方法和字段的引用解析為內存地址
初始化
初始化階段是類加載最后一個階段,前面的類加載階段之后,除了在加載階段可以自定義類加載器以外,其它操作都由 JVM 主導。到了初始階段,才開始真正執行類中定義的 Java 程序代碼。
初始化階段是執行類構造器方法的過程。方法是由編譯器自動收集類中的類變量的賦值操作和靜態語句塊中的語句合并而成的。虛擬機會保證子方法執行之前,父類的方法已經執行完畢,如果一個類中沒有對靜態變量賦值也沒有靜態語句塊,那么編譯器可以不為這個類生成()方法。
注意以下幾種情況不會執行類初始化:
1. 通過子類引用父類的靜態字段,只會觸發父類的初始化,而不會觸發子類的初始化。
2. 定義對象數組,不會觸發該類的初始化。
3. 常量在編譯期間會存入調用類的常量池中,本質上并沒有直接引用定義常量的類,不會觸發定義常量所在的類。
4. 通過類名獲取 Class 對象,不會觸發類的初始化。
5. 通過 Class.forName 加載指定類時,如果指定參數 initialize 為 false 時,也不會觸發類初始化,其實這個參數是告訴虛擬機,是否要對類進行初始化。
6. 通過 ClassLoader 默認的 loadClass 方法,也不會觸發初始化動作。