日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java虚拟机学习 - 类加载器(ClassLoader)

發布時間:2025/7/14 java 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java虚拟机学习 - 类加载器(ClassLoader) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

類加載器

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


類與類加載器

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

類加載器分類:

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

啟動類加載器(Bootstrap ClassLoader):

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

擴展類加載器(Extension ClassLoader):

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

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

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

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

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

雙親委托模型:

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

public abstract class ClassLoader {private static native void registerNatives();static {registerNatives();}// The parent class loader for delegationprivate ClassLoader parent;// Hashtable that maps packages to certsprivate Hashtable package2certs = new Hashtable(11); }


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

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

類加載器SPI:

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

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

如果類需要resolve,在調用resolveClass進行鏈接。

protected synchronized Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{// First, check if the class has already been loadedClass 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實例對象的緩存中尋找已加載的類,調用的為native方法。

protected final Class<?> findLoadedClass(String name) {if (!checkName(name))return null;return findLoadedClass0(name);}private native final Class findLoadedClass0(String name);

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

protected Class<?> findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);}

findSystemClass ?此方法是從sun.misc.Launcher$AppClassLoader中尋找類,如果未找到,則繼續從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 此方法負責將二進制字節流轉換為Class對象,這個方法對于自定義類加載器而言非常重要。如果二進制的字節碼的格式不符合jvm class文件格式規范,則拋出ClassFormatError異常;如果生成的類名和二進制字節碼不同,則拋出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 verificationprivate 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 ?這是最常見的異常,產生這個異常的原因為在當前的ClassLoader 中加載類時,未找到類文件,

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

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


? ? ? ? ? ? ?本文原文鏈接:http://blog.csdn.net/java2000_wl/article/details/8222876 轉載請注明出處!

轉載于:https://www.cnblogs.com/java-wl/archive/2012/11/25/2923111.html

總結

以上是生活随笔為你收集整理的Java虚拟机学习 - 类加载器(ClassLoader)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。