本篇博客將寫一點關於JVM的東西,涉及JVM運行時數據區、類加載的過程、類加載器、ClassLoader、雙親委派機制、自定義類加載器等,這些都是博主本身的一點理解,若是有誤,歡迎你們評論拍磚~java
class文件加載至內存,連接(校驗、解析),初始化;最終造成JVM能夠直接使用的JAVA類型的過程。bootstrap
加載:在方法區造成類的運行時數據結構;在堆裏面造成該類的Class對象,做爲訪問方法區的入口。數組
連接:class文件是否存在問題;一些符號引號替換成直接引用。
初始化:初始化一個類,先初始化它的父類。虛擬機會保證一個類的初始化在多線程環境中被正確加鎖和同步。安全
要使用類A,必須先加載類A;加載類A,就會把靜態變量、靜態塊合併初始化,而後在調用構造器。注意類的加載和初始化,只有一次。服務器
上文已經說了,類加載器的做用就是:將class文件的字節碼內容加載到內存中,並將這些靜態數據轉化成方法區中的運行時數據結構,在堆中生成一個表明這個類的Class對象,做爲方法區類數據的訪問入口。數據結構
類加載器的層次結構
多線程
引導類加載器bootstrap classloaderapp
加載JAVA核心庫($JAVA_HOME/jre/lib/rt.jar),原生代碼實現(C++),並不繼承自java.lang.ClassLoader。ide
擴展類加載器extensions classloaderspa
JAVA能夠提供一個擴展目錄($JAVA_HOME/jre/ext/*.jar)來加載Java類。
由sun.misc.Launcher.ExtClassLoader實現
應用程序類加載器application classloader(也稱系統類加載器)
通常來講,JAVA應用的類由它加載,即加載路徑是classpath下的路徑。
由sun.misc.Launcher.AppClassLoader實現。
自定義類加載器
開發人員繼承java.lang.ClassLoader實現本身的類加載器
ClassLoader的基本職責就是:
第一,根據指定的類名稱,找到或者生成對應的字節碼,並根據字節碼生成class對象
第二,加載JAVA應用所需的資源,如配置文件等。
ClassLoader的組合模式
引導類加載器是原生代碼實現,咱們獲取不到,因此是null。
ClassLoader重要API
getParent():該類加載器的父類加載器
loadClass(String name):加載名稱爲name的類,並返回Class實例。
加載順序是:先交給擴展類加載器加載,若是加載不到,交給引導類加載器加載,加載不到,交給本身去加載,若是本身也加載不到,那麼ClassNotFoundException。【雙親委派機制】 若是要改變類的加載順序,那麼能夠override該方法。
findClass(String name),不是加載,僅僅是查找而已
findLoadedClass(String name),查找已經被加載過的
defineClass(String name,byte[] b, int off ,int len),能夠把字節數組的內容轉換成JAVA類,並會返回Class實例。
類加載器的代理模式:就是把加載指定類的過程交給其餘加載器。
JAVA默認使用的類加載器代理模式是:雙親委派機制。
雙親委派機制:
就是某個特定的類加載器接到加載類的請求時,首先將加載任務委託給父類加載器,依次追溯,好比說從應用加載器委託給擴展類加載器,從擴展類加載器委託給引導類加載器。這種委託,直至委託到層次最高的類加載器,即引導類加載器,若是委託的父類加載器能夠完成加載任務,那麼成功返回;只有父類加載器沒法完成時,纔去本身加載。
能夠看出雙親委派機制的意思就是優先父類加載器加載!
試想若是咱們定義了一個java.lang.String類,根據雙親委派機制,那麼JDK只會加載它本身的String。這顯然保證了Java核心庫的類型安全。
雙親委派機制不是惟一的選擇
雖然JDK默認的類加載機制是雙親委派機制,可是並非全部都採用,好比有些服務器,如Tomcat,雖然也採用代理的方式加載,可是加載順序卻偏偏和雙親委派機制相反,它是首先嚐試加載這個類,只有加載不到的狀況下,纔去讓父類加載器代理加載。
爲何會這樣呢,不是說雙親委派很安全麼?
其實就是在安全,和靈活方面進行取捨!
MyClassLoader:
重寫findClass:
Test:
通常狀況下,自定義類加載器,須要繼承自ClassLoader。
首先來講,能夠檢查請求的類是否已經被自定義的類加載器加載;若是加載了,那麼直接返回;不然,那麼交給父類加載器,就是進行雙親委派;若是雙親委派也加載不到,那麼交給自定義類加載器進行「自定義的方式」來加載類。
另外,被2個不一樣的類加載加載的同一個類,JVM不會認爲是一個類。