Java和其餘語言不一樣的是,Java是運行於Java虛擬機(JVM)。這就意味着編譯後的代碼是以
一種和平臺無關的格式保存的,而不是某種特定的機器上運行的格式。這種格式和傳統的可
執行代碼格式有不少重要的區別。具體來講,不一樣於C或者C++程序,Java程序不是一個獨
立的可執行文件,而是由不少分開的類文件組成,每一個類文件對應一個Java類。 另外,這
些類文件並非立刻加載到內存,而是當程序須要的時候才加載。 類加載器就是Java虛擬
機中用來把類加載到內存的工具。並且,Java類加載器也是用Java實現的。這樣你就不須要
對Java虛擬機有深刻的理解就能夠很容易建立本身的類加載器了。
爲何要建立類加載器?
既然Java虛擬金已經有了類加載器,咱們還要本身建立其餘的呢?問得好。默認的類加載器
只知道如何從本地系統加載類。當你的程序徹底在本機編譯的話,默認的類加載器通常都工
做的很好。可是Java中最激動人心的地方之一就是很容易的從網絡上而不僅是本地加載類。
舉個例子,瀏覽器能夠經過自定義的類加載器加載類。 還有
不少加載類的方式。除了簡單的從本地或者網絡外,你還能夠經過自定義Java中最激動人心
的地方之一:
* 執行非信任代碼前自動驗證數字簽名
* 根據用戶提供的密碼解密代碼
* 根據用戶的須要動態的建立類
你關心的任何東西都能方便的以字節碼的形式集成到你的應用中
自定義類加載器的例子
若是你已經使用過JDK(Java軟件開發包)中的appletviewer(小應用程序瀏覽器)或者其餘
Java嵌入式瀏覽器,你就已經使用了自定義類加載器了。Sun剛剛發佈Java語言的時候,最
使人興奮的一件事就是觀看Java如何執行從遠程網站下載的代碼。執行從遠程站點經過HTT
P鏈接傳送來的字節碼看起來有點難以想象。之因此可以工做,由於Java有安裝自定義類加
載器的能力。小應用程序瀏覽器包含了一個類加載器,這個類加載器不從本地找Java類,而
是訪問遠程服務器,經過HTTP加載原始字節碼文件,而後在Java虛擬機中轉化爲Java類。當
然類加載器還作了其餘的不少事情:他們阻止不安全的Java類,並且保持不一樣頁面上的不一樣
小程序不會互相干擾。Luke Gorrie寫的一個包Echidna是一個開放的Java軟件包,他容許在
一個Java虛擬機中安全的運行多個Java應用程序。它經過使用自定義類加載器給每一個應用程
序一份類文件的拷貝來阻止應用程序之間的干擾。html
java類加載器 :java
java中默認有三種類加載器:引導類加載器,擴展類加載器,系統類加載器(也叫應用類加載器)bootstrap
類加載器是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構造器的參數: app
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給出了能夠運行的自定義類加載器示例。