免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Java中的類加載器

首先聲明,我是因?yàn)榭戳薎mportNew網(wǎng)站上的幾篇關(guān)于類加載器的文章之后,才萌生了寫這篇文章的想法。所以在寫這篇文章時(shí),參考了該網(wǎng)站上的幾篇相關(guān)的文章,但是加入了很多自己的理解,絕對(duì)不是抄襲。



從java的動(dòng)態(tài)性到類加載機(jī)制


我們知道,Java是一種動(dòng)態(tài)語言。那么怎樣理解這個(gè)“動(dòng)態(tài)”呢?或者說一門語言具備了什么特性,才能稱之為動(dòng)態(tài)語言呢?對(duì)于java,我是這樣理解的。


我們都知道JVM(java虛擬機(jī))執(zhí)行的不是本地機(jī)器碼指令,而是執(zhí)行一種稱之為字節(jié)碼的指令(存在于class文件中)。這就要求虛擬機(jī)在真正執(zhí)行字節(jié)碼之前,先把相關(guān)的class文件加載到內(nèi)存中。虛擬機(jī)不是一次性加載所有需要的class文件,因?yàn)樗趫?zhí)行的時(shí)候根本不會(huì)知道以后會(huì)用到哪些class文件。它是每用到一個(gè)類,就會(huì)在運(yùn)行時(shí)“動(dòng)態(tài)地”加載和這個(gè)類相關(guān)的class文件。這就是java被稱之為動(dòng)態(tài)性語言的根本原因。除了動(dòng)態(tài)加載類之外,還會(huì)動(dòng)態(tài)的初始化類,對(duì)類進(jìn)行動(dòng)態(tài)鏈接。動(dòng)態(tài)初始化和動(dòng)態(tài)鏈接放在其他文章中進(jìn)行介紹。本文中只關(guān)心類的加載。


在JVM中負(fù)責(zé)對(duì)類進(jìn)行加載的正是本文要介紹的類加載器(ClassLoader),所以,類加載器是JVM不可或缺的重要組件。



java中的類加載器及類加載器工作原理


java中(指的是javase)有三種類加載器。每個(gè)類加載器在創(chuàng)建的時(shí)候已經(jīng)指定他們對(duì)應(yīng)的目錄, 也就是說每個(gè)類加載器去哪里加載類是確定的,我認(rèn)為在ClassLoader類中應(yīng)該會(huì)有g(shù)etTargetPath()之類的方法, 得到他們對(duì)應(yīng)的路徑,找了找jdk的文檔,發(fā)現(xiàn)是沒有的。以下是這三種類加載器和他們對(duì)應(yīng)的路徑:


 * AppClassLoader  --   加載classpath指定的路徑中的類

 * ExtClassLoader   --   加載jre/lib/ext目錄下或者java.ext.dirs系統(tǒng)屬性定義的目錄下的類

 * BootStrap           --   加載JRE/lib/rt.jar中的類


那么類加載器是如何工作的呢?可以參看jdk中ClassLoader類的源碼。這個(gè)類的實(shí)現(xiàn)使用了模板方法模式,首先是loadClass方法來加載類,loadClass方法又調(diào)用了findClass方法,該方法讀取并返回類文件的數(shù)據(jù),findClass方法返回后,loadClass方法繼續(xù)調(diào)用defineClass方法,將返回的數(shù)據(jù)加工成虛擬機(jī)運(yùn)行時(shí)可識(shí)別的類型信息。所以,我們?nèi)绻_發(fā)自己的類加載器,只需要繼承jdk中的ClassLoader類,并覆蓋findClass方法就可以了,剩下的而工作,父類會(huì)完成。其他java平臺(tái)有的根據(jù)自己的需求,實(shí)現(xiàn)了自己特定的類加載器,例如javaee平臺(tái)中的tomcat服務(wù)器,Android平臺(tái)中的dalvik虛擬機(jī)也定義了自己的類加載器。


虛擬機(jī)加載類有兩種方式,一種方式就是上面提到的ClassLoader.loadClass()方法,另一種是使用反射API,Class.forName()方法,其實(shí)Class.forName()方法內(nèi)部也是使用的ClassLoader。Class類中forName方法的實(shí)現(xiàn)如下:


  1. public static Class<?> forName(String name, boolean initialize,  
  2.                    ClassLoader loader)  
  3.         throws ClassNotFoundException  
  4.     {  
  5.     if (loader == null) {  
  6.         SecurityManager sm = System.getSecurityManager();  
  7.         if (sm != null) {  
  8.         ClassLoader ccl = ClassLoader.getCallerClassLoader();  
  9.         if (ccl != null) {  
  10.             sm.checkPermission(  
  11.             SecurityConstants.GET_CLASSLOADER_PERMISSION);  
  12.         }  
  13.         }  
  14.     }  
  15.     return forName0(name, initialize, loader);  
  16.     }  
  17.   
  18.     /** Called after security checks have been made. */  
  19.     private static native Class forName0(String name, boolean initialize,  
  20.                         ClassLoader loader)  
  21.     throws ClassNotFoundException;  


類加載器的三個(gè)特性


類加載器有三個(gè)特性,分別為委派,可見性和單一性,其他文章上對(duì)這三個(gè)特性的介紹如下:


 * 委托機(jī)制是指將加載一個(gè)類的請(qǐng)求交給父類加載器,如果這個(gè)父類加載器不能夠找到或者加載這個(gè)類,那么再加載它。

 * 可見性的原理是子類的加載器可以看見所有的父類加載器加載的類,而父類加載器看不到子類加載器加載的類。

 * 單一性原理是指僅加載一個(gè)類一次,這是由委托機(jī)制確保子類加載器不會(huì)再次加載父類加載器加載過的類。


其中,委派機(jī)制是基礎(chǔ),在其他資料中也把這種機(jī)制叫做類加載器的雙親委派模型,其實(shí)說的是同一個(gè)意思??杉有院蛦我恍允且蕾囉谖蓹C(jī)制的。


以下代碼測(cè)試類加載器的委派機(jī)制:

  1. ClassLoader appClassLoader = ClassLoaderTest.class.getClassLoader();  
  2. System.out.println(appClassLoader); //sun.misc.Launcher$AppClassLoader@19821f  
  3.   
  4.   
  5. ClassLoader extClassLoader = appClassLoader.getParent();  
  6. System.out.println(extClassLoader);  //sun.misc.Launcher$ExtClassLoader@addbf1  
  7. //AppClassLoader的父加載器是ExtClassLoader  
  8.   
  9. System.out.println(extClassLoader.getParent()); //null  
  10. //ExtClassLoader的父加載器是null, 也就是BootStrap,這是由c語言實(shí)現(xiàn)的  

由打印結(jié)果可知,加載我們自己編寫的類的加載器是AppClassLoader,AppClassLoader的父加載器是ExtClassLoader,在而ExtClassLoader的父加載器返回結(jié)果為null,這說明他的附加載器是BootStrap,這個(gè)加載器是和虛擬機(jī)緊密聯(lián)系在一起的,在虛擬機(jī)啟動(dòng)時(shí),就會(huì)加載jdk中的類。它是由C實(shí)現(xiàn)的,沒有對(duì)應(yīng)的java對(duì)象,所以返回null。但是在邏輯上,BootStrap仍是ExtClassLoader的父加載器。也就是說每當(dāng)ExtClassLoader加載一個(gè)類時(shí),總會(huì)委托給BootStrap加載。



系統(tǒng)類加載器和線程上下文類加載器


在java中,還存在兩個(gè)概念,分別是系統(tǒng)類加載器和線程上下文類加載器。

其實(shí)系統(tǒng)類加載器就是AppClassLoader應(yīng)用程序類加載器,它兩個(gè)值得是同一個(gè)加載器,以下代碼可以驗(yàn)證:

  1. ClassLoader appClassLoader = ClassLoaderTest.class.getClassLoader();  
  2. System.out.println(appClassLoader); //sun.misc.Launcher$AppClassLoader@19821f  
  3.   
  4. ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader();  
  5. System.out.println(sysClassLoader);  //sun.misc.Launcher$AppClassLoader@19821f  
  6. //由上面的驗(yàn)證可知, 應(yīng)用程序類加載器和系統(tǒng)類加載器是相同的, 因?yàn)榈刂肥且粯拥?nbsp; 

這兩個(gè)類加載器對(duì)應(yīng)的輸出,不僅類名相同,連對(duì)象的哈希值都是一樣的,這充分說明系統(tǒng)類加載器和應(yīng)用程序類加載器不僅是同一個(gè)類,更是同一個(gè)類的同一個(gè)對(duì)象。

每個(gè)線程都會(huì)有一個(gè)上下文類加載器,由于在線程執(zhí)行時(shí)加載用到的類,默認(rèn)情況下是父線程的上下文類加載器, 也就是AppClassLoader。

  1. new Thread(new Runnable() {  
  2.       
  3.     @Override  
  4.     public void run() {  
  5.         ClassLoader threadcontextClassLosder = Thread.currentThread().getContextClassLoader();  
  6.         System.out.println(threadcontextClassLosder); //sun.misc.Launcher$AppClassLoader@19821f  
  7.     }  
  8. }).start();  

這個(gè)子線程在執(zhí)行時(shí)打印的信息為sun.misc.Launcher$AppClassLoader@19821f,可以看到和主線程中的AppClassLoader是同一個(gè)對(duì)象(哈希值相同)。


也可以為線程設(shè)置特定的類加載器,這樣的話,線程在執(zhí)行時(shí)就會(huì)使用這個(gè)特定的類加載器來加載使用到的類。如下代碼:


  1. Thread th = new Thread(new Runnable() {  
  2.       
  3.     @Override  
  4.     public void run() {  
  5.         ClassLoader threadcontextClassLosder = Thread.currentThread().getContextClassLoader();  
  6.         System.out.println(threadcontextClassLosder); //jg.zhang.java.testclassloader.ClassLoaderTest$3@1b67f74  
  7.     }  
  8. });  
  9.   
  10. th.setContextClassLoader(new ClassLoader() {});  
  11.   
  12. th.start();  

在線程運(yùn)行之前,為它設(shè)置了一個(gè)匿名內(nèi)部類的類加載器對(duì)象,線程運(yùn)行時(shí),輸出的信息為:jg.zhang.java.testclassloader.ClassLoaderTest$3@1b67f74,也就是我們?cè)O(shè)置的那個(gè)類加載器對(duì)象。



類加載器的可見性


下面驗(yàn)證類加載器的可見性,也就是 子類的加載器可以看見所有的父類加載器加載的類,而父類加載器看不到子類加載器加載的類。

以下代碼使用父加載器ExtClassLoader加載子加載器AppClassLoader路徑下的類,由輸出可知,是不可能實(shí)現(xiàn)的。

  1. try {  
  2.     Class.forName("jg.zhang.java.testConcurrent.Person", true,   
  3.             ClassLoaderTest.class.getClassLoader().getParent());  
  4.     System.out.println("1 -- 類被加載");  
  5. } catch (ClassNotFoundException e) {  
  6.     //e.printStackTrace();  
  7.     System.out.println("1 -- 未找到類");  
  8. }  

輸出為 :1 -- 未找到類 。說明拋出了ClassNotFoundException異常。原因是讓ExtClassLoader加載 jg.zhang.java.testConcurrent.Person這個(gè)類因?yàn)檫@個(gè)類不在jre/lib/ext目錄下或者java.ext.dirs系統(tǒng)屬性定義的目錄下,所以拋出ClassNotFoundException。所以父加載器不能加載應(yīng)該被子加載器加載的類。也就是說這個(gè)類在父加載器中不可見。這種機(jī)制依賴于委派機(jī)制。


下面代碼使用子加載器AppClassLoader 加載父加載器BootStrap中的類,這是可以實(shí)現(xiàn)的。

  1. try {  
  2.     Class.forName("java.lang.String", true,   
  3.             ClassLoaderTest.class.getClassLoader());  
  4.     System.out.println("2 -- 類被加載");  
  5. } catch (ClassNotFoundException e) {  
  6.     //e.printStackTrace();  
  7.     System.out.println("2 -- 未找到類");  
  8. }  

輸出為:2 -- 類被加載。說明成功加載了String類。是因?yàn)樵谥付ㄓ葾ppClassLoader加載String類時(shí),由AppClassLoader一直委派到BootStrap加載。雖然是由子加載器的父加載器加載的,但是也可以說,父加載器加載的類對(duì)于子加載器來說是可見的。這同樣依賴于委派機(jī)制。其實(shí)在虛擬機(jī)啟動(dòng)初期,java.lang.String已經(jīng)被BootStrap預(yù)加載了,這時(shí)再次加載,虛擬機(jī)發(fā)現(xiàn)已經(jīng)加載,不會(huì)再重復(fù)加載。這同時(shí)也證明了類加載器的單一性。



測(cè)試代碼


到此為止,類加載器的知識(shí)就全部講完了。以下是整個(gè)測(cè)試代碼:

  1. package jg.zhang.java.testclassloader;  
  2.   
  3.   
  4. /** 
  5.  * 參考ImportNew上的一篇文章<<類加載器的工作原理>>, 
  6.  * 文章地址:http://www.importnew.com/6581.html 
  7.  *  
  8.  * Java類加載器基于三個(gè)機(jī)制:委托、可見性和單一性。 
  9.  * 委托機(jī)制是指將加載一個(gè)類的請(qǐng)求交給父類加載器,如果這個(gè)父類加載器不能夠找到或者加載這個(gè)類,那么再加載它。 
  10.  * 可見性的原理是子類的加載器可以看見所有的父類加載器加載的類,而父類加載器看不到子類加載器加載的類。 
  11.  * 單一性原理是指僅加載一個(gè)類一次,這是由委托機(jī)制確保子類加載器不會(huì)再次加載父類加載器加載過的類。 
  12.  *  
  13.  * 三種類加載器: 每個(gè)類加載器在創(chuàng)建的時(shí)候已經(jīng)指定他們對(duì)應(yīng)的目錄, 也就是說每個(gè)類加載器去哪里加載類是確定的 
  14.  * 我認(rèn)為在ClassLoader類中應(yīng)該會(huì)有g(shù)etTargetPath()之類的方法, 得到他們對(duì)應(yīng)的路徑,找了找jdk的文檔,發(fā)現(xiàn)是沒有的. 
  15.  * AppClassLoader  --   加載classpath指定的路徑中的類 
  16.  * ExtClassLoader  --   加載jre/lib/ext目錄下或者java.ext.dirs系統(tǒng)屬性定義的目錄下的類 
  17.  * BootStrap       --   加載JRE/lib/rt.jar中的類 
  18.  *  
  19.  *  
  20.  *  
  21.  * @author zhangjg 
  22.  * 
  23.  */  
  24. public class ClassLoaderTest {  
  25.   
  26.       
  27.     public static void main(String[] args) {  
  28.         test1();  
  29.         test2();  
  30.         test3();  
  31.     }  
  32.   
  33.     /** 
  34.      * 驗(yàn)證線程上下文類加載器 
  35.      */  
  36.     private static void test3() {  
  37.         /** 
  38.          * 1 每個(gè)線程都會(huì)有一個(gè)上下文類加載器,由于在線程執(zhí)行時(shí)加載用到的類,默認(rèn)情況下是父線程 
  39.          * 的上下文類加載器, 也就是AppClassLoader 
  40.          */  
  41.         new Thread(new Runnable() {  
  42.               
  43.             @Override  
  44.             public void run() {  
  45.                 ClassLoader threadcontextClassLosder = Thread.currentThread().getContextClassLoader();  
  46.                 System.out.println(threadcontextClassLosder); //sun.misc.Launcher$AppClassLoader@19821f  
  47.             }  
  48.         }).start();  
  49.           
  50.         /** 
  51.          * 2 也可以給創(chuàng)建的線程設(shè)定特定的上下文類加載器 
  52.          */  
  53.         Thread th = new Thread(new Runnable() {  
  54.               
  55.             @Override  
  56.             public void run() {  
  57.                 ClassLoader threadcontextClassLosder = Thread.currentThread().getContextClassLoader();  
  58.                 System.out.println(threadcontextClassLosder); //jg.zhang.java.testclassloader.ClassLoaderTest$3@1b67f74  
  59.             }  
  60.         });  
  61.           
  62.         th.setContextClassLoader(new ClassLoader() {});  
  63.           
  64.         th.start();  
  65.     }  
  66.   
  67.     /** 
  68.      * 測(cè)試可見性,可見性依賴于委托機(jī)制 
  69.      */  
  70.     private static void test2() {  
  71.           
  72.         /** 
  73.          * 1 讓ExtClassLoader加載 jg.zhang.java.testConcurrent.Person這個(gè)類 
  74.          * 因?yàn)檫@個(gè)類不在jre/lib/ext目錄下或者java.ext.dirs系統(tǒng)屬性定義的目錄下 
  75.          * 所以拋出ClassNotFoundException 
  76.          *  
  77.          * 所以父加載器不能加載應(yīng)該被子加載器加載的類,這個(gè)類在父加載器中不可見 
  78.          * 這種機(jī)制依賴于委派機(jī)制 
  79.          */  
  80.           
  81.         try {  
  82.             Class.forName("jg.zhang.java.testConcurrent.Person", true,   
  83.                     ClassLoaderTest.class.getClassLoader().getParent());  
  84.             System.out.println("1 -- 類被加載");  
  85.         } catch (ClassNotFoundException e) {  
  86.             //e.printStackTrace();  
  87.             System.out.println("1 -- 未找到類");  
  88.         }  
  89.           
  90.           
  91.         /** 
  92.          * 2 讓AppClassLoader加載java.lang.String類 
  93.          * 沒有拋出異常,說明類被正常加載了 
  94.          * 雖然是由AppClassLoader一直委派到BootStrap而加載的 
  95.          * 所以可以說,父加載器加載的類對(duì)于子加載器來說是可見的,這同樣依賴于委派機(jī)制 
  96.          *  
  97.          * 其實(shí)在虛擬機(jī)啟動(dòng)初期,java.lang.String已經(jīng)被BootStrap預(yù)加載了 
  98.          * 這時(shí)再次加載,虛擬機(jī)發(fā)現(xiàn)已經(jīng)加載,不會(huì)再重復(fù)加載 
  99.          */  
  100.         try {  
  101.             Class.forName("java.lang.String", true,   
  102.                     ClassLoaderTest.class.getClassLoader());  
  103.             System.out.println("2 -- 類被加載");  
  104.         } catch (ClassNotFoundException e) {  
  105.             //e.printStackTrace();  
  106.             System.out.println("2 -- 未找到類");  
  107.         }  
  108.           
  109.     }  
  110.   
  111.     /** 
  112.      * 驗(yàn)證三種類加載器的父子關(guān)系 
  113.      */  
  114.     private static void test1() {  
  115.         ClassLoader appClassLoader = ClassLoaderTest.class.getClassLoader();  
  116.         System.out.println(appClassLoader); //sun.misc.Launcher$AppClassLoader@19821f  
  117.           
  118.         ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader();  
  119.         System.out.println(sysClassLoader);  //sun.misc.Launcher$AppClassLoader@19821f  
  120.         //由上面的驗(yàn)證可知, 應(yīng)用程序類加載器和系統(tǒng)類加載器是相同的, 因?yàn)榈刂肥且粯拥?nbsp; 
  121.           
  122.         ClassLoader extClassLoader = appClassLoader.getParent();  
  123.         System.out.println(extClassLoader);  //sun.misc.Launcher$ExtClassLoader@addbf1  
  124.         //AppClassLoader的父加載器是ExtClassLoader  
  125.           
  126.         System.out.println(extClassLoader.getParent()); //null  
  127.         //ExtClassLoader的父加載器是null, 也就是BootStrap,這是由c語言實(shí)現(xiàn)的  
  128.   
  129.     }  
  130.   
  131. }  


本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Classloader總結(jié)
JVM虛擬機(jī)------類加載器
java基礎(chǔ):Q8. 類加載器的相關(guān)知識(shí)
類加載器機(jī)器委托機(jī)制的深入
javaEE防盜版-java之類加載
JVM加載class文件的原理機(jī)制
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服