筆記:類加載器

  對於任意一個類,都須要由加載它的類加載器和這個類自己一同確立其在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;
        }
    }
相關文章
相關標籤/搜索