對於任意一個類,都須要由加載它的類加載器和這個類自己一同確立其在Java虛擬機中的惟一性,每個類加載器,都擁有一個獨立的類名稱空間;這句話的意思是比較兩個類是否「相等」,只有在這兩個類是由同一個類加載器加載的前提下才有意義,不然,即便這兩個類來源於同一個Class文件,被同一個虛擬機加載,只要加載他們的類加載器不一樣,那這兩個類一定不相等。java
「相等」是指類對象的 equals() 方法、isAssiggnableFrom() 方法、isInstance() 方法的返回結果,也有 使用 instanceof 關鍵字作對象所屬關係斷定 等等。this
啓動類加載器(Bootstrap ClassLoader):這個類加載器負責把放在 <JAVA_HOME>\lib 目錄中的、或者被 -Xbootclasspath參數所指定的路徑中,而且能被虛擬機識別的類庫加載到虛擬機內存中。開發者不能直接引用這個類加載器。spa
擴展類加載器(Extension ClassLoader):負責加載 <JAVA_HOME>\lib\ext 目錄中的、或者被 java.ext.dirs 系統變量所指定的路徑中的全部類庫,這個類加載器能夠被開發者直接使用。設計
應用程序類加載器(Application ClassLoader):這個類加載器是 ClassLoader的 getSystemClassLoader() 方法的返回值;負責加載用戶類路徑(ClassPath)上所指定的類庫,開發者能夠直接使用這個類加載器,若是應用程序中沒有自定義過本身的類加載器,通常狀況下這個就是程序中默認的類加載器。code
雙親委派模型:對象
雙親委派模型要求除了頂層的啓動類加載器以外,其他的類加載器都應當有本身的父類加載器。這裏類加載器之間的父子關係通常不會以繼承關係實現,而是以組合的關係來實現。blog
工做過程:若是一個類加載器收到了類加載的請求,它首先不會本身去嘗試加載這個類,而是把這個請求委託給父類加載器去完成,每個層次的類加載器都是如此,所以全部的加載器請求最終都應該傳到頂層的啓動類加載器中,只有當父類加載器反饋本身沒法完成這個加載請求(它的搜索範圍中沒有找到所需的類)時,子類加載器纔會嘗試本身去加載。繼承
做用:類隨着它的類加載器一塊兒具有了一種帶有優先級的層次關係。例如類java.lang.Object
,它由啓動類加載器加載。雙親委派模型保證任何類加載器收到的對java.lang.Object
的加載請求,最終都是委派給處於模型最頂端的啓動類加載器進行加載,所以Object類在程序的各類類加載器環境中都是同一個類。內存
說明:雙親委派模型不是一個強制性的約束模型,而是Java設計者推薦給開發者的類加載器實現方式。在絕大多數類加載器都遵循這個模型,可是也有一小部分爲了實現更好的功能不是這個模型。開發
雙親委派模型的實現:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }