http://blog.csdn.net/xyang81/article/details/7292380html
http://blog.csdn.net/tonytfjing/article/details/47212291java
https://www.cnblogs.com/zhouyuqin/p/5217609.html算法
4. 類加載器的階層體系
討論了這麼多之後,接下來咱們仔細研究一下 Java 的類加載器的工做原理:
當執行 java ***.class 的時候, java.exe 會幫助咱們找到 JRE ,接着找到位於 JRE 內部的 jvm.dll ,這纔是真正的 Java 虛擬機器 , 最後加載動態庫,激活 Java 虛擬機器。虛擬機器激活之後,會先作一些初始化的動做,好比說讀取系統參數等。一旦初始化動做完成以後,就會產生第一個類加載器―― Bootstrap Loader , Bootstrap Loader 是由 C++ 所撰寫而成,這個 Bootstrap Loader 所作的初始工做中,除了一些基本的初始化動做以外,最重要的就是加載 Launcher.java 之中的 ExtClassLoader ,並設定其 Parent 爲 null ,表明其父加載器爲 BootstrapLoader 。而後 Bootstrap Loader 再要求加載 Launcher.java 之中的 AppClassLoader ,並設定其 Parent 爲以前產生的 ExtClassLoader 實體。這兩個加載器都是以靜態類的形式存在的。這裏要請你們注意的是, Launcher$ExtClassLoader.class 與 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加載,因此 Parent 和由哪一個類加載器加載沒有關係。 api
這三個加載器就構成咱們的 Java 類加載體系。他們分別從如下的路徑尋找程序所須要的類: 安全
BootstrapLoader : sun.boot.class.path
ExtClassLoader: java.ext.dirs
AppClassLoader: java.class.path網絡
在加載階段,虛擬機須要完成如下3件事情:數據結構
一、原理介紹jvm
ClassLoader使用的是雙親委託模型來搜索類的,每一個ClassLoader實例都有一個父類加載器的引用(不是繼承的關係,是一個包含的關係),虛擬機內置的類加載器(Bootstrap ClassLoader)自己沒有父類加載器,但能夠用做其它ClassLoader實例的的父類加載器。當一個ClassLoader實例須要加載某個類時,它會試圖親自搜索某個類以前,先把這個任務委託給它的父類加載器,這個過程是由上至下依次檢查的,首先由最頂層的類加載器Bootstrap ClassLoader試圖加載,若是沒加載到,則把任務轉交給Extension ClassLoader試圖加載,若是也沒加載到,則轉交給App ClassLoader 進行加載,若是它也沒有加載獲得的話,則返回給委託的發起者,由它到指定的文件系統或網絡等URL中加載該類。若是它們都沒有加載到這個類時,則拋出ClassNotFoundException異常。不然將這個找到的類生成一個類的定義,並將它加載到內存當中,最後返回這個類在內存中的Class實例對象。.net
二、爲何要使用雙親委託這種模型呢?htm
由於這樣能夠避免重複加載,當父親已經加載了該類的時候,就沒有必要子ClassLoader再加載一次。考慮到安全因素,咱們試想一下,若是不使用這種委託模式,那咱們就能夠隨時使用自定義的String來動態替代java核心api中定義的類型,這樣會存在很是大的安全隱患,而雙親委託的方式,就能夠避免這種狀況,由於String已經在啓動時就被引導類加載器(Bootstrcp ClassLoader)加載,因此用戶自定義的ClassLoader永遠也沒法加載一個本身寫的String,除非你改變JDK中ClassLoader搜索類的默認算法。
三、JVM在搜索類的時候,如何判斷兩個class相同呢?
JVM在斷定兩個class是否相同時,不只要判斷兩個類名是否相同,並且要判斷是否由同一個類加載器實例加載的。只有二者同時知足的狀況下,JVM才認爲這兩個class是相同的。就算兩個class是同一份class字節碼,若是被兩個不一樣的ClassLoader實例所加載,JVM也會認爲它們是兩個不一樣class。
好比網絡上的一個Java類org.classloader.simple.NetClassLoaderSimple,javac編譯以後生成字節碼文件NetClassLoaderSimple.class,ClassLoaderA和ClassLoaderB這兩個類加載器並讀取了NetClassLoaderSimple.class文件,並分別定義出了java.lang.Class實例來表示這個類,對於JVM來講,它們是兩個不一樣的實例對象,但它們確實是同一份字節碼文件,若是試圖將這個Class實例生成具體的對象進行轉換時,就會拋運行時異常java.lang.ClassCaseException,提示這是兩個不一樣的類型。