為了深入了解Java的ClassLoader機制我們先來做以下實驗
package javalang;
public class Test {
public static void main(String[] args) {
char[] c = toCharArray();
String s = new String( c);
}
}
String類有一個Package權限的構造函數String(int offset int length char[] array)按照默認的訪問權限由於Test屬於javalang包因此理論上應該可以訪問String的這個構造函數編譯通過!執行時結果如下
Exception in thread main javalangSecurityException:
Prohibited package name:
javalang
at javalangClassLoaderdefineClass(Unknown Source)
at javasecuritySecureClassLoaderdefineClass(Unknown Source)
at URLClassLoaderdefineClass(Unknown Source)
at URLClassLoaderaccess$(Unknown Source)
at URLClassLoader$run(Unknown Source)
at javasecurityAccessControllerdoPrivileged(Native Method)
at URLClassLoaderfindClass(Unknown Source)
at javalangClassLoaderloadClass(Unknown Source)
at sunmiscLauncher$AppClassLoaderloadClass(Unknown Source)
at javalangClassLoaderloadClass(Unknown Source)
at javalangClassLoaderloadClassInternal(Unknown Source)
奇怪吧?要弄清為什麼會有SecurityException就必須搞清楚ClassLoader的機制
Java的ClassLoader就是用來動態裝載class的ClassLoader對一個class只會裝載一次JVM使用的ClassLoader一共有種
啟動類裝載器標准擴展類裝載器類路徑裝載器和網絡類裝載器
這種ClassLoader的優先級依次從高到低使用所謂的雙親委派模型確切地說如果一個網絡類裝載器被請求裝載一個javalangInteger它會首先把請求發送給上一級的類路徑裝載器如果返回已裝載則網絡類裝載器將不會裝載這個javalangInteger如果上一級的類路徑裝載器返回未裝載它才會裝載javalangInteger
類似的類路徑裝載器收到請求後(無論是直接請求裝載還是下一級的ClassLoader上傳的請求)它也會先把請求發送到上一級的標准擴展類裝載器這樣一層一層上傳於是啟動類裝載器優先級最高如果它按照自己的方式找到了javalangInteger則下面的ClassLoader 都不能再裝載javalangInteger盡管你自己寫了一個javalangInteger試圖取代核心庫的javalangInteger是不可能的因為自己寫的這個類根本無法被下層的ClassLoader裝載
再說說Package權限Java語言規定在同一個包中的class如果沒有修飾符默認為Package權限包內的class都可以訪問但是這還不夠准確確切的說只有由同一個ClassLoader裝載的class才具有以上的Package權限比如啟動類裝載器裝載了javalangString類路徑裝載器裝載了我們自己寫的javalangTest它們不能互相訪問對方具有Package權限的方法這樣就阻止了惡意代碼訪問核心類的Package權限方法
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26236.html