小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Java虛擬機學習(10):類加載器(ClassLoader)

 冬O_O煦 2016-11-19


來源:java2000_wl

鏈接:blog.csdn.net/java2000_wl/article/details/8222876


類加載器(ClassLoader)用來加載 class字節(jié)碼到 Java 虛擬機中。一般來說,Java 虛擬機使用 Java 類的方式如下:Java 源文件在經(jīng)過 Javac之后就被轉換成 Java 字節(jié)碼文件(.class 文件)。類加載器負責讀取 Java 字節(jié)代碼,并轉換成 java.lang.Class 類的一個實例。每一個這樣的實例用來表示一個 Java 類。實際的情況可能更加復雜,比如 Java 字節(jié)代碼可能是通過工具動態(tài)生成的,也可能是通過網(wǎng)絡下載。


類與類加載器


類加載器雖然只用于實現(xiàn)類的加載動作,但它在Java程序中起到的作用卻遠遠不限于類加載階段。對于任意一個類,都需要由加載它的類加載器和這個類本身一同確立其在Java虛擬中的唯一性。說通俗一些,比較兩個類是否“相等”,只有在兩個類是由同一個類加載器的前提之下才有意義,否則,即使這兩個類來源于同一個class文件,只要加載它的類加載器不同,那這兩個類必定不相等。這里所指的“相等”包括代表類的Class對象的equal方法、isAssignableFrom()、isInstance()方法及instance關鍵字返回的結果。


類加載器分類:



主要分為Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader和User Defined ClassLoader。


啟動類加載器(Bootstrap ClassLoader):


這個類加載器使用C++語言實現(xiàn),并非ClassLoader的子類。主要負責加載存放在JAVA_HOME /  jre /  lib / rt.jar里面所有的class文件,或者被-Xbootclasspath參數(shù)所指定路徑中以rt.jar命名的文件。


擴展類加載器(Extension ClassLoader):


這個加載器由sun.misc.Launcher$ExtClassLoader實現(xiàn),它負責加載AVA_HOME /  lib / ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫。


應用程序類加載器(Application ClassLoader):


這個加載器由sun.misc.Launcher$AppClassLoader實現(xiàn),它負責加載classpath對應的jar及目錄。一般情況下這個就是程序中默認的類加載器。


自定義類加載器(User Defined ClassLoader):


開發(fā)人員繼承ClassLoader抽象類自行實現(xiàn)的類加載器,基于自行開發(fā)的ClassLoader可用于并非加載classpath中(例如從網(wǎng)絡上下載的jar或二進制字節(jié)碼)、還可以在加載class文件之前做些小動作 如:加密等。


雙親委托模型:


上圖中所展示的類加載器之間的這種層次關系,就稱為類加載器的雙親委托模型。雙親委托模型要求除了頂層的啟動類加載器外,其余的類加載器都應當有自己的父類加載器。這里類加載器之間的父子關系一般不會以繼承的關系來實現(xiàn),而是使用組合關系來復用父加載器的代碼。


public abstract class ClassLoader {  

 

    private static native void registerNatives();  

    static {  

        registerNatives();  

    }  

 

    // The parent class loader for delegation  

    private ClassLoader parent;  

 

    // Hashtable that maps packages to certs  

    private Hashtable package2certs = new Hashtable(11);  

}


雙親委托的工作過程:如果一個類加載器收到了一個類加載請求,它首先不會自己去加載這個類,而是把這個請求委托給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求最終都應該傳送到頂層的啟動類加載器中,只有當父類加載器反饋自己無法完成加載請求(它管理的范圍之中沒有這個類)時,子加載器才會嘗試著自己去加載。


使用雙親委托模型來組織類加載器之間的關系,有一個顯而易見的好處就是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關系,例如java.lang.Object存放在rt.jar之中,無論那個類加載器要加載這個類,最終都是委托給啟動類加載器進行加載,因此Object類在程序的各種類加載器環(huán)境中都是同一個類,相反,如果沒有雙親委托模型,由各個類加載器去完成的話,如果用戶自己寫一個名為java.lang.Object的類,并放在classpath中,應用程序中可能會出現(xiàn)多個不同的Object類,java類型體系中最基本安全行為也就無法保證。


類加載器SPI:


java.lang.ClassLoader 類提供的幾個關鍵方法:


loadClass: 此方法負責加載指定名字的類,首先會從已加載的類中去尋找,如果沒有找到;從parent ClassLoader[ExtClassLoader]中加載;如果沒有加載到,則從Bootstrap ClassLoader中嘗試加載(findBootstrapClassOrNull方法), 如果還是加載失敗,則拋出異常ClassNotFoundException, 在調(diào)用自己的findClass方法進行加載。如果要改變類的加載順序可以覆蓋此方法;如果加載順序相同,則可以通過覆蓋findClass方法來做特殊處理,例如:解密,固定路徑尋找等。當通過整個尋找類的過程仍然未獲取Class對象,則拋出ClassNotFoundException異常。


如果類需要resolve,在調(diào)用resolveClass進行鏈接。


  protected synchronized Class loadClass(String name, boolean resolve)  

throws ClassNotFoundException  

   {  

// First, check if the class has already been loaded  

Class c = findLoadedClass(name);  

if (c == null) {  

    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.  

        c = findClass(name);  

    }  

}  

if (resolve) {  

    resolveClass(c);  

}  

return c;  

   }


findLoadedClass 此方法負責從當前ClassLoader實例對象的緩存中尋找已加載的類,調(diào)用的為native方法。


protected final Class findLoadedClass(String name) {  

(!checkName(name))  

 return null;  

urn findLoadedClass0(name);  

}  

 

private native final Class findLoadedClass0(String name);


findClass 此方法直接拋出ClassNotFoundException異常,因此要通過覆蓋loadClass或此方法來以自定義的方式加載相應的類。


protected Class findClass(String name) throws ClassNotFoundException {  

ow new ClassNotFoundException(name);  

}


findSystemClass  此方法是從sun.misc.Launcher$AppClassLoader中尋找類,如果未找到,則繼續(xù)從BootstrapClassLoader中尋找,如果仍然未找到,返回null


   protected final Class findSystemClass(String name)  

throws ClassNotFoundException  

   {  

ClassLoader system = getSystemClassLoader();  

if (system == null) {  

    if (!checkName(name))  

    throw new ClassNotFoundException(name);  

           Class cls = findBootstrapClass(name);  

           if (cls == null) {  

               throw new ClassNotFoundException(name);  

           }   

    return cls;  

}  

return system.loadClass(name);  

   }


defineClass 此方法負責將二進制字節(jié)流轉換為Class對象,這個方法對于自定義類加載器而言非常重要。如果二進制的字節(jié)碼的格式不符合jvm class文件格式規(guī)范,則拋出ClassFormatError異常;如果生成的類名和二進制字節(jié)碼不同,則拋出NoClassDefFoundError;如果加載的class是受保護的、采用不同簽名的,或者類名是以java.開頭的,則拋出SecurityException異常。


protected final Class defineClass(String name, byte[] b, int off, int len,  

                     ProtectionDomain protectionDomain)  

    throws ClassFormatError  

    {  

         return defineClassCond(name, b, off, len, protectionDomain, true);  

    }  

 

    // Private method w/ an extra argument for skipping class verification  

    private final Class defineClassCond(String name,  

                                           byte[] b, int off, int len,  

                                           ProtectionDomain protectionDomain,  

                                           boolean verify)  

        throws ClassFormatError  

    {  

    protectionDomain = preDefineClass(name, protectionDomain);  

 

    Class c = null;  

        String source = defineClassSourceLocation(protectionDomain);  

 

    try {  

        c = defineClass1(name, b, off, len, protectionDomain, source,  

                             verify);  

    } catch (ClassFormatError cfe) {  

        c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,  

                                       source, verify);  

    }  

 

    postDefineClass(c, protectionDomain);  

    return c;  

    }


resolveClass 此方法負責完成Class對象的鏈接,如果鏈接過,則直接返回。


常見異常:


ClassNotFoundException  這是最常見的異常,產(chǎn)生這個異常的原因為在當前的ClassLoader 中加載類時,未找到類文件,


NoClassDefFoundError  這個異常是因為  加載到的類中引用到的另外類不存在,例如要加載A,而A中盜用了B,B不存在或當前的ClassLoader無法加載B,就會拋出這個異常。


LinkageError 該異常在自定義ClassLoader的情況下更容易出現(xiàn),主要原因是此類已經(jīng)在ClassLoader加載過了,重復的加載會造成該異常。


本系列:



關注「ImportNew」

看更多 Java 技術精選文章

↓↓

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多