JVM將類加載過程分爲三個步驟:裝載(Load),連接(Link)和初始化(Initialize)連接又分爲三個步驟,以下圖所示:
1) 裝載:查找並加載類的二進制數據; java
2)連接: 程序員
驗證:確保被加載類的正確性; 數據庫
準備:爲類的靜態變量分配內存,並將其初始化爲默認值; tomcat
解析:把類中的符號引用轉換爲直接引用; 安全
3)初始化:爲類的靜態變量賦予正確的初始值; 服務器
那爲何我要有驗證這一步驟呢?首先若是由編譯器生成的class文件,它確定是符合JVM字節碼格式的,可是萬一有高手本身寫一個class文件,讓JVM加載並運行,用於惡意用途,就不妙了,所以這個class文件要先過驗證這一關,不符合的話不會讓它繼續執行的,也是爲了安全考慮吧。 網絡
準備階段和初始化階段看似有點牟盾,實際上是不牟盾的,若是類中有語句:private static int a = 10,它的執行過程是這樣的,首先字節碼文件被加載到內存後,先進行連接的驗證這一步驟,驗證經過後準備階段,給a分配內存,由於變量a是static的,因此此時a等於int類型的默認初始值0,即a=0,而後到解析(後面在說),到初始化這一步驟時,才把a的真正的值10賦給a,此時a=10。 數據結構
2. 類的初始化 spa
類何時才被初始化: .net
1)建立類的實例,也就是new一個對象
2)訪問某個類或接口的靜態變量,或者對該靜態變量賦值
3)調用類的靜態方法
4)反射(Class.forName("com.lyj.load"))
5)初始化一個類的子類(會首先初始化子類的父類)
6)JVM啓動時標明的啓動類,即文件名和類名相同的那個類
只有這6中狀況纔會致使類的類的初始化。
類的初始化步驟:
1)若是這個類尚未被加載和連接,那先進行加載和連接
2)假如這個類存在直接父類,而且這個類尚未被初始化(注意:在一個類加載器中,類只能初始化一次),那就初始化直接的父類(不適用於接口)
3)加入類中存在初始化語句(如static變量和static塊),那就依次執行這些初始化語句。
3.類的加載
類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,而後在堆區建立一個這個類的java.lang.Class對象,用來封裝類在方法區類的對象。看下面2圖
類的加載的最終產品是位於堆區中的Class對象
Class對象封裝了類在方法區內的數據結構,而且向Java程序員提供了訪問方法區內的數據結構的接口
加載類的方式有如下幾種:
1)從本地系統直接加載
2)經過網絡下載.class文件
3)從zip,jar等歸檔文件中加載.class文件
4)從專有數據庫中提取.class文件
5)將Java源文件動態編譯爲.class文件(服務器)
4.加載器
來自http://blog.csdn.net/cutesource/article/details/5904501
JVM的類加載是經過ClassLoader及其子類來完成的,類的層次關係和加載順序能夠由下圖來描述:
1)Bootstrap ClassLoader
負責加載$JAVA_HOME中jre/lib/rt.jar裏全部的class,由C++實現,不是ClassLoader子類
2)Extension ClassLoader
負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包
3)App ClassLoader
負責記載classpath中指定的jar包及目錄中class
4)Custom ClassLoader
屬於應用程序根據自身須要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader
加載過程當中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視爲已加載此類,保證此類只全部ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。