Java進階-Java中的類裝載器和命名空間

來源:互聯網
上載者:User

類裝載器的功能及分類

顧名思義,類裝載器是用來把類(class)裝載進JVM的。JVM規範定義了兩種類型的類裝載器:啟動類裝載器(bootstrap)和使用者自訂裝載器(user-defined class loader)。

bootstrap是JVM內建的類裝載器,用來裝載核心類庫,如java.lang.*等。如java.lang.Object是由bootstrap裝載的。

Java提供了抽象類別ClassLoader,所有使用者自訂類裝載器都執行個體化自ClassLoader的子類。 System Class Loader是一個非凡的使用者自訂類裝載器,由JVM的實現者提供,在編程者不非凡指定裝載器的情況下預設裝載使用者類。系統類別裝載器可以通過ClassLoader.getSystemClassLoader() 方法得到。

例1,測試你所使用的JVM的ClassLoader

/*LoaderSample1.java*/public class LoaderSample1 {    public static void main(String[] args) {        Class c;        ClassLoader cl;        cl = ClassLoader.getSystemClassLoader();        System.out.println(cl);        while (cl != null) {            cl = cl.getParent();            System.out.println(cl);        }        try {            c = Class.forName("java.lang.Object");            cl = c.getClassLoader();            System.out.println("java.lang.Object's loader is "   cl);            c = Class.forName("LoaderSample1");            cl = c.getClassLoader();            System.out.println("LoaderSample1's loader is "   cl);        } catch (Exception e) {            e.printStackTrace();        }    }}

在我的機器上(Sun Java 1.5)的運行結果

C:\java>java LoaderSample1
sun.misc.Launcher$AppClassLoader@82ba41
sun.misc.Launcher$ExtClassLoader@923e30
java.lang.Object's loader is null
LoaderSample1's loader is sun.misc.Launcher$AppClassLoader@82ba41

第一行表示,系統類別裝載器執行個體化自類sun.misc.Launcher$AppClassLoader

第二行表示,系統類別裝載器的parent執行個體化自類sun.misc.Launcher$ExtClassLoader

第三行表示,系統類別裝載器parent的parent為bootstrap

第四行表示,核心類java.lang.Object是由bootstrap裝載的

第五行表示,使用者類LoaderSample1是由系統類別裝載器裝載的

parent delegation模型

從1.2版本開始,Java引入了雙親委託模型,從而更好的保證Java平台的安全。在此模型下,當一個裝載器被請求裝載某個類時,它首先委託自己的parent去裝載,若parent能裝載,則返回這個類所對應的Class對象,若parent不能裝載,則由parent的要求者去裝載。

1所示,loader2的parent為loader1,loader1的parent為system class loader。假設loader2被要求裝載類MyClass,在parent delegation模型下,loader2首先請求loader1代為裝載,loader1再請求系統類別裝載器去裝載MyClass。若系統裝載器能成功裝載,則將MyClass所對應的Class對象的reference返回給loader1,loader1再將reference返回給loader2,從而成功將類MyClass裝載進虛擬機器。若系統類別裝載器不能裝載MyClass,loader1會嘗試裝載MyClass,若loader1也不能成功裝載,loader2會嘗試裝載。若所有的parent及loader2本身都不能裝載,則裝載失敗。

若有一個能成功裝載,實際裝載的類裝載器被稱為定義類裝載器,所有能成功返回Class對象的裝載器(包括定義類裝載器)被稱為初始類裝載器。1所示,假設loader1實際裝載了MyClass,則loader1為MyClass的定義類裝載器,loader2和loader1為MyClass的初始類裝載器。

圖 1 parent delegation模型

需要指出的是,Class Loader是對象,它的父子關係和類的父子關係沒有任何關係。一對父子loader可能執行個體化自同一個Class,也可能不是,甚至父loader執行個體化自子類,子loader執行個體化自父類。假設MyClassLoader繼續自ParentClassLoader,我們可以有如下父子loader:

ClassLoader loader1 = new MyClassLoader();//參數 loader1 為 parentClassLoader loader2 = new ParentClassLoader(loader1);                         

那麼parent delegation模型為什麼更安全了?因為在此模型下使用者自訂的類裝載器不可能裝載應該由父親裝載器裝載的可靠類,從而防止不可靠甚至惡意的代碼代替由父親裝載器裝載的可靠代碼。實際上,類裝載器的編寫者可以自由選擇不用把請求委託給parent,但正如上所說,會帶來安全的問題。

命名空間及其作用

每個類裝載器有自己的命名空間,命名空間由所有以此裝載器為初始類裝載器的類組成。不同命名空間的兩個類是不可見的,但只要得到類所對應的Class對象的reference,還是可以訪問另一命名空間的類。

例2示範了一個命名空間的類如何使用另一命名空間的類。在例子中,LoaderSample2由系統類別裝載器裝載,LoaderSample3由自訂的裝載器loader負責裝載,兩個類不在同一命名空間,但LoaderSample2得到了LoaderSample3所對應的Class對象的reference,所以它可以訪問LoaderSampl3中公用的成員(如age)。

例2 不同命名空間的類的訪問

/*LoaderSample2.java*/import java.net.*;import java.lang.reflect.*;public class LoaderSample2 {    public static void main(String[] args) {try {String path = System.getProperty("user.dir");URL[] us = {new URL("file://" path "/sub/")};ClassLoader loader = new URLClassLoader(us);Class c = loader.loadClass("LoaderSample3");Object o = c.newInstance();Field f = c.getField("age");int age = f.getInt(o);System.out.println("age is " age);} catch (Exception e) {e.printStackTrace();}}}

/*sub/Loadersample3.java*/public class LoaderSample3 {    static {        System.out.println("LoaderSample3 loaded");    }    public int age = 30;}

編譯:

javac LoaderSample2.java; javac sub/LoaderSample3.java

運行:java LoaderSample2

LoaderSample3 loadedage is 30                        

從運行結果中可以看出,在類LoaderSample2中可以建立處於另一命名空間的類LoaderSample3中的對象並可以訪問其公用成員age。

運行時包(runtime package)

由同一類裝載器定義裝載的屬於相同包的類組成了運行時包,決定兩個類是不是屬於同一個運行時包,不僅要看它們的包名是否相同,還要看類裝載器是否相同。只有屬於同一運行時包的類才能互相訪問包可見的類和成員。這樣的限制避免了使用者自己的代碼冒充核心類庫的類訪問核心類庫包可見成員的情況。假設使用者自己定義了一個類java.lang.Yes,並用使用者自訂的類裝載器裝載,由於java.lang.Yes和核心類庫java.lang.*由不同的裝載器裝載,它們屬於不同的運行時包,所以java.lang.Yes不能訪問核心類庫java.lang中類的包可見的成員。

總結

在簡單討論了類裝載器,parent delegation模型,命名空間,運行時包後,相信大家已經對它們的作用有了一定的瞭解。命名空間並沒有完全禁止屬於不同空間的類的互相訪問,雙親委託模型加強了Java的安全,運行時包增加了對包可見成員的保護。

轉自:http://www2.oklinux.cn/html/developer/java/base/20080120/45998.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.