Java虛擬機把描述類的數據從Class文件加載到內存,並對數據進行校驗、解析和初始化,最終造成能夠被虛擬機直接使用的Java類型,這個過程被稱做虛擬機的類加載機制。 ——《深刻理解Java虛擬機》html
加載、鏈接(驗證、準備、解析)、初始化、使用、卸載。 java
這五個階段的順序是肯定的,類加載必須按照這種順序「開始」(這些階段一般是交叉混合進行的,因此執行順序與完成順序可能並非按照開始順序)。web
《Java虛擬機規範》中並無進行強制約束,可是對於初始化階段,則是嚴格規定了有且只有六種狀況必須當即對類進行「初始化」(而加載、驗證、準備天然須要在此之 前開始):緩存
接口初始化與類初始化不一樣,只要是體如今上述第3點,當一個接口在初始化時,並不要求其父接口所有都完成了初始化,只有在真正使用到父接口的時候(如引用接口中定義的常量)纔會初始化。安全
在加載階段,Java虛擬機須要完成如下三件事情:數據結構
總結一下,就是讀取Class文件,將類結構存到方法區,再在堆內建立一個Class對象。oracle
驗證是鏈接階段的第一步,這一階段的目的是確保Class文件的字節流中包含的信息符合《Java虛 擬機規範》的所有約束要求,保證這些信息被看成代碼運行後不會危害虛擬機自身的安全。jvm
準備階段是正式爲類中定義的變量(即靜態變量,被static修飾的變量)分配內存並設置類變量初始值的階段。編輯器
🌰1
//對於static變量來講,在準備階段結束以後,value的值是0,而非123,等到初始化時纔會設置成123。 public static int value = 123; 🌰2 //而對於常量來講,在準備階段就會被設置成123。 public final static int value = 123; 複製代碼
解析階段是Java虛擬機將常量池內的符號引用替換爲直接引用的過程。url
符號引用就是字符串,這個字符串包含足夠的信息,以供實際使用時能夠找到相應的位置。你好比說某個方法的符號引用,如:「java/io/PrintStream.println:(Ljava/lang/String;)V」。裏面有類的信息,方法名,方法參數等信息。
關於符號引用能夠看看R大的回答。JVM裏的符號引用如何存儲?
還有《Java虛擬機規範》第四章class文件格式的第四節常量池 有介紹符號引用的格式。
初始化階段就是執行類構造器clinit()方法的過程。
clinit()方法是由編譯器自動收集類中的全部類變量的賦值動做和靜態語句塊(static{}塊)中的語句合併產生的。就是static變量和static方法合併後的結果。
以下圖,static的變量賦值和方法會被合併到static{}(javap反編譯的結果,static{}就是clinit())裏。
當AppClassLoader加載一個class時,它首先不會本身去嘗試加載這個類,而是把類加載請求委派給父類加載器ExtClassLoader
去完成。
當ExtClassLoader加載一個class時,它首先也不會本身去嘗試加載這個類,而是把類加載請求委派給BootStrapClassLoader
去完成。
若是BootStrapClassLoader
加載失敗(例如在$JAVA_HOME/jre/lib
裏未查找到該class),會使用ExtClassLoader
來嘗試加載;
若ExtClassLoader
也加載失敗,則會使用AppClassLoader
來加載,若是AppClassLoader
也加載失敗,則會報出異常ClassNotFoundException
。
防止重複加載,防止核心庫被修改。
使同名類(🌰java.lang.Object)在程序的各類類加載器環境中都可以保證是同一個類。
《深刻理解Java虛擬機》《Java虛擬機規範》
圖片來源《深刻理解Java虛擬機》
本文使用 mdnice 排版