Java類加載原理及類加載器

Java和其他語言不同的是,Java是運行於Java虛擬機(JVM)。這就意味着編譯後的代碼是以一種和平臺無關的格式保存的,而不是某種特定的機器上運行的格式。這種格式和傳統的可執行代碼格式有很多重要的區別。具體來說,不同於C或者C++程序,Java程序不是一個獨立的可執行文件,而是由很多分開的類文件組成,每個類文件對應一個Java類。 另外,這些類文件並不是馬上加載到內存,而是當程序需要的時候才加載。 類加載器就是Java虛擬機中用來把類加載到內存的工具。而且,Java類加載器也是用Java實現的。這樣你就不需要對Java虛擬機有深入的理解就可以很容易創建自己的類加載器了。


爲什麼要創建類加載器?
既然Java虛擬金已經有了類加載器,我們還要自己創建其他的呢?問得好。默認的類加載器只知道如何從本地系統加載類。當你的程序完全在本機編譯的話,默認的類加載器一般都工作的很好。但是Java中最激動人心的地方之一就是很容易的從網絡上而不只是本地加載類。
舉個例子,瀏覽器可以通過自定義的類加載器加載類。 還有很多加載類的方式。除了簡單的從本地或者網絡外,你還可以通過自定義Java中最激動人心的地方之一:


* 執行非信任代碼前自動驗證數字簽名
* 根據用戶提供的密碼解密代碼
* 根據用戶的需要動態的創建類


你關心的任何東西都能方便的以字節碼的形式集成到你的應用中


自定義類加載器的例子
如果你已經使用過JDK(Java軟件開發包)中的appletviewer(小應用程序瀏覽器)或者其他Java嵌入式瀏覽器,你就已經使用了自定義類加載器了。Sun剛剛發佈Java語言的時候,最令人興奮的一件事就是觀看Java如何執行從遠程網站下載的代碼。執行從遠程站點通過HTTP連接傳送來的字節碼看起來有點不可思議。之所以能夠工作,因爲Java有安裝自定義類加載器的能力。小應用程序瀏覽器包含了一個類加載器,這個類加載器不從本地找Java類,而是訪問遠程服務器,通過HTTP加載原始字節碼文件,然後在Java虛擬機中轉化爲Java類。當然類加載器還做了其他的很多事情:他們阻止不安全的Java類,而且保持不同頁面上的不同小程序不會互相干擾。Luke Gorrie寫的一個包Echidna是一個開放的Java軟件包,他允許在一個Java虛擬機中安全的運行多個Java應用程序。它通過使用自定義類加載器給每個應用程序一份類文件的拷貝來阻止應用程序之間的干擾。

 

 

 

 

 


java類加載器 :

java中默認有三種類加載器:引導類加載器,擴展類加載器,系統類加載器(也叫應用類加載器)

類加載器是Java最強大的特徵之一。但是開發者常常忘記類加載組件。類加載器是在運行時負責尋找和加載類文件的類。Java允許使用不同的類加載器,甚至自定義的類加載器。

 

Java 程序包含很多類文件,每一個都與單個Java類相對應,這些類文件不像靜態C程序,一次性加載入內存,它們隨時需要隨時加載。這就是類加載器與衆不同的地 方。它從源文件(通常是.class 或 .jar文件)獲得不依賴平臺的字節碼,然後將它們加載到JVM內存空間,所以它們能被解釋和執行。默認狀態下,應用程序的每個類由 java.lang.ClassLoader加載。因爲它可以被繼承,所以可以自由地加強其功能。

 

使用自定義類加載器的原因

  默認的 java.lang.ClassLoader僅僅可以從加載本地文件系統的類。Java被設計成不論本地磁盤或網絡都有足夠的彈性加載類,並且可以在加載 之前處理特殊事物。例如:應用程序可以檢查Web站點或FTP上插入類的更新版本並且自動校驗數字簽名確保執行可信任的代碼。許多衆所周知的軟件都使用自 己的類加載器。

 

通常默認加載器是所謂的bootstrap類加載器;它負責加載諸如java.lang.Object等關鍵類和加 載其他rt.jar文件的運行時代碼到內存。因爲Java語言規範沒有提供bootstrap類加載器的詳細信息,不同的JVM可能有不同的類加載器。如 果看到網頁上有applets在運行,則它使用的是自定義類加載器。嵌入到瀏覽器中的applet閱讀器包含了可以訪問遠程服務器上站點的類加載器,它可 以通過HTTP加載原始字節碼文件,並且在JVM中將它們轉換成類。

 

  類加載器(除了bootstrap類加載器)有父類加載器,這些父類是基本加載器的加載器實例。最重要的一點是設置正確的父加載器。然後可以使用 類加載器的getParent()方法實現委派類請求(例如:自定義類加載器找不到使用專門方法的類時)。此時必須爲將父加載器作爲 java.lang.ClassLoader構造器的參數:

public class MyClassLoader extends ClassLoader{ public MyClassLoader() { super(MyClassLoader.class.getClassLoader()); } }

 

 


 

 

loadClass(String name)方法是ClassLoader的入口。名字參數是完全資格類名(FQCN),例如關於包類名。如果父加載器設置正確,當請求 MyClassLoader中的loadClass(String name)方法加載類,但又找不到需要加載的類時,則首先會詢問父加載器。如果父加載器也找不到此類,則調用findClass(String name)方法。默認狀態下findClass(String name)會拋出ClassNotFoundException例外,很多開發人員都很清楚這個例外。自定義類加載器的開發者都希望從 java.lang.ClassLoader繼承時跳過這個方法。

 

findClass()方法的目標是爲MyClassLoader容納所有專門代碼,此時不需要重複其他代碼(例如當加載失敗時調用系統 ClassLoader)。在此方法中,ClassLoader需要從原文件中獲取字節碼。一旦找到字節碼則會調用defineClass()方法。 ClassLoader實例調用此方法是非常重要的。因此,如果兩個ClassLoader實例定義了來自不同或相同原文件的字節碼,則被定義的類也將區 別對待。

 

我們給出兩個相似的類加載器MyClassLoader1 和 MyClassLoader2,它們都可以從相同的源文件找到MyCoolClass字節碼。如果一個程序通過這兩個加載器分別獨立加載 MyCoolClass實例(coolClass1通過MyClassLoader1加載, coolClass2通過MyClassLoader2加載),MyCoolClass.class能夠被獨立定義。執行下面的代碼:

MyCoolClass coolClass1 = (MyCoolClass)coolClass2;

 

  將得到一個ClassCastException例外。(開發者如果沒有很好的理解類加載機制則經常碰到這樣的情況。)因爲它們是不同的加載器 所定義的,JVM將它們看成不同的類。雖然它們是相同類型的類並且從相同的源文件加載,但是變量coolClass1和coolClass2不兼容。

 

不論是否跳過findClass() 或 loadClass(),getSystemClassLoader()方法將以實際ClassLoader對象的形式直接訪問系統 ClassLoader。也可以通過調用findSystemClass(String name)方法間接訪問。getParent()方法允許獲得父加載器。Listing A給出了可以運行的自定義類加載器示例。

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/zdwzzu2006/archive/2008/04/05/2253982.aspx

 

 

相關鏈接:

★  Java知識點彙總 

全球軟件項目外包平臺 兼職做外包 掙Money!

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