類加載器和委託機制的理解

      Java虛擬機中可以安裝多個類加載器,系統默認三個主要類加載器,每個類負責加載特定位置的類:BootStrap,ExtClassLoader,AppClassLoader
       類加載器也是Java類,因爲其他是java類的類加載器本身也要被類加載器加載,顯然必須有第一個類加載器不是不是java類,這正是BootStrap。

       Java虛擬機中的所有類裝載器採用具有父子關係的樹形結構進行組織,在實例化每個類裝載器對象時,需要爲其指定一個父級類裝載器對象或者默認採用系統類裝載器爲其父級類加載。

     如下是類加載器的關係圖:


接下來用代碼簡單說明一下他們的關係

package javatribe.fts.generic;

public class ClassLoaderTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//得到一個類加載器,因爲類加載器也是一個類,然後得到類加載器的一個對象
		//然後得到這個對象的字節碼,根據這份字節碼得到類加載器的名字
		//輸出結果sun.misc.Launcher$AppClassLoaders說明ClassLoaderTest是該類加載器加載的
		System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
		//輸出爲null不代表它沒有類加載器,說明它有一個特殊的類加載器
		//是bootstrap類加載器它不是一個java類java對象,它是嵌套在java虛擬機裏面的,用c++的二進制實現的
		System.out.println(System.class.getClassLoader());
		
		//用代碼輸出說明三個類加載器的關係
		ClassLoader loader=ClassLoaderTest.class.getClassLoader();
		while(loader!=null){
			System.out.println(loader.getClass().getName());
			loader=loader.getParent();
		}
		//打印頂級加載器的名稱
		System.out.println(loader);
	}

}

最後輸出的結果是:

sun.misc.Launcher$AppClassLoader
null
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null
對於他們的關係已經在類註釋的地方已經說明好了。

用myeclipse的打包工具將ClassLoaderTest輸出成jre/lib/ext目錄下的fts.jar包,再在myeclipse中運行這個類,運行結果顯示爲ExtClassLoadr。此時的環境狀態是classpath目錄有ClassLoaderTest.class,ext/itcast.jar包中也有ClassLoaderTest.class,這時候我們就需要了解類加載的具體過程和原理了。

 點擊Finish之後然後再運行剛纔的類,這時候輸出另一種結果。這個就說明了三個類加載器的所負責的地方是不一樣的。

sun.misc.Launcher$ExtClassLoader
null
sun.misc.Launcher$ExtClassLoader
null
接下來有如下問題:

當Java虛擬機要加載一個類時,到底派出哪個類加載器去加載呢?
       首先當前線程的類加載器去加載線程中的第一個類。
       如果類A中引用了類B,Java虛擬機將使用加載類A的類裝載器來加載類B。 
      還可以直接調用ClassLoader.loadClass()方法來指定某個類加載器去加載某個類。
每個類加載器加載類時,又先委託給其上級類加載器。
      當所有祖宗類加載器沒有加載到類,回到發起者類加載器,還加載不了,則拋ClassNotFoundException,不是再 去找發起者類加載器的兒子,因爲沒有getChild方法,即使有,那有多個兒子,找哪一個呢?
      對着類加載器的層次結構圖和委託加載原理,解釋先前將ClassLoaderTest輸出成jre/lib/ext目錄下的fts.jar包中後,運行結果爲ExtClassLoader的原因。
     每個ClassLoader本身只能分別加載特定位置和目錄中的類,但它們可以委託其他的類裝載器去加載類,這就是類加載器的委託模式。類裝載器一級級委託到BootStrap類加載器,當BootStrap無法加載當前所要加載的類時,然後才一級級回退到子孫類裝載器去進行真正的加載。當回退到最初的類裝載器時,如果它自己也不能完成類的裝載,那就應報告ClassNotFoundException異常。
      那麼能不能自己寫個類叫java.lang.System,爲了不讓我們寫System類,類加載採用委託機制,這樣可以保證爸爸們優先,也就是總是使用爸爸們能找到的類,這樣總是使用java系統提供的System。所以自己寫的System類就加載不到了。那麼可不可以自己寫一個特殊加載類來加載自己寫的System類呢?
       如果把先前編寫的類加入到jdk的rt.jar中,會有怎樣的效果呢?結果是不行!!!結論是是不能隨意將自己的class文件加入進rt.jar文件中的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章