1. 程式人生 > >Java的類裝載器(Class Loader)和名稱空間(NameSpace)

Java的類裝載器(Class Loader)和名稱空間(NameSpace)

摘要

Java的類裝載器是Java動態性的核心,本文將向大家簡要介紹Java的類裝載器,及相關的parent delegation模型,名稱空間,執行時包等概念,同時討論一些在學習中容易混淆的問題。 

類裝載器的功能及分類

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

bootstrap是JVM自帶的類裝載器,用來裝載核心類庫,如java.lang.*等。由例1可以看出,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.4.2)的執行結果

[email protected]
[email protected]
null 
java.lang.Object's loader is null
LoaderSample1's loader is [email protected]

第一行表示,系統類裝載器例項化自類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 為 parent
ClassLoader 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 loaded
age is 30

從執行結果中可以看出,在類LoaderSample2中可以建立處於另一名稱空間的類LoaderSample3中的物件並可以訪問其公共成員age。

執行時包(runtime package)

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

總結

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

相關推薦

Java裝載(Class Loader)名稱空間(NameSpace)

摘要 Java的類裝載器是Java動態性的核心,本文將向大家簡要介紹Java的類裝載器,及相關的parent delegation模型,名稱空間,執行時包等概念,同時討論一些在學習中容易混淆的問題。  類裝載器的功能及分類 顧名思義,類裝載器是用來把類(class)裝載進JVM的。JVM規範定義了兩種型別的

JAVA載入、註解動態代理

一.類載入器 1.什麼是類載入器,作用是什麼 類載入器就載入位元組碼檔案(.class) 2.類載入器的種類 類載入器有三種,不同載入器載入不同 BootStrap:引導類載入器:載入都是最基礎的檔案 ExtClassLoader:擴充套

JAVA安全管理裝載

SecurityManager相關概念理解 Java語言具有完善的安全框架,從程式語言,編譯器、解釋程式到Java虛擬機器, 都能確保Java系統不被無效的程式碼或敵對的編譯器暗中破壞,基本上,它們保證 了Java程式碼按預定的規則運作。但是,當我們需要逾越這些限制時,

Java中的反射裝載

首先通過一個簡單的例子看一下Java中的反射,如下,是一個Car類: Car.java public class Car { private String brand; private String color; privat

Java載入( CLassLoader ) 死磕9: 上下文載入原理案例

【正文】Java類載入器(  CLassLoader ) 死磕9:  上下文載入器原理和案例 本小節目錄 9.1. 父載入器不能訪問子載入器的類 9.2. 一個寵物工廠介面 9.3. 一個寵物工廠管理類 9.4 APPClassLoader不能訪問子載入器中的類 9.5. 執行緒上下文

Java載入( CLassLoader ) 死磕8: 使用ASM,載入實現AOP

【正文】Java類載入器(  CLassLoader ) 死磕8:  使用ASM,和類載入器實現AOP 本小節目錄 8.1. ASM位元組碼操作框架簡介 8.2. ASM和訪問者模式 8.3. 用於增強位元組碼的事務類 8.4 通過ASM訪問註解 8.5. 通過ASM注入AOP事務程式

Java載入雙親委派模型.md

0.類載入過程 一般來說,類載入分為3個過程,載入,連結和初始化。 1.載入階段,是Java將位元組碼資料從不同資料來源讀取到JVM中,並對映為JVM認可的Class物件,這裡的資料來源可能有Jar包,class檔案,甚至網路資料來源等。如果輸入資料不是ClassFile結構,則會丟

java基礎(六)抽象(abstract class介面(Interface)

抽象類(abstract class)和介面(Interface)是Java語言中對於抽象類定義進行支援的兩種機制,賦予了Java強大的面向物件能力。 二者具有很大的相似性,甚至可以相互替換,因此很多開發者在進行抽象類定義時對於abstractclass和Interface的選擇顯得比較

抽象(abstract class介面(interface)有什麼異同?【Java面試題】

1、抽象類可以包含非抽象的方法,而介面中的方法必須是抽象的。 2、繼承抽象類在Java語言體系中體現一種繼承關係,在合理的繼承關係中,父類和派生類比如按存在is-a關係。而實現介面則體現一種has-a

檔案分析Java裝載過程方法的呼叫的呼叫

class Print{ Print(String s){ System.out.println("Step "+s); } Print(String s,double i){ System.out.println("Step "+s+" 隨機數 "+i); } } abstract cl

java載入雙親委派載入機制

java類載入器分類詳解  1、Bootstrap ClassLoader:啟動類載入器,也叫根類載入器,負責載入java的核心類庫,例如(%JAVA_HOME%/lib)目錄下的rt.jar(包含Sy

Java 構造呼叫成員初始化順序

呼叫基類構造器。首先構造繼承關係最上層類的構造器,然後是下一層匯出類的構造器,以此類推,直至最底層的匯出類。 按宣告順序呼叫成員的初始化方法。 呼叫匯出類構造器的主體。 demo class

java載入動態代理

import java.lang.reflect.*; import java.util.ArrayList; import java.util.Collection; public class ProxyTest { public static void main(String[] args) throw

JVM概述裝載

1.JVM是執行在作業系統之上的,與硬體沒有半毛錢關係。 2.我就不用說jvm是什麼意思,接下來我來說我對jvm的理解 3.雙

Java載入雙親委派機制

前言 之前詳細介紹了Java類的整個載入過程(類載入機制詳解)。雖然,篇幅較長,但是也不要被內容嚇到了,其實每個階段都可以用一句話來概括。 1)載入:查詢並載入類的二進位制位元組流資料。 2)驗證:保證被載入的類的正確性。 3)準備:為類的靜態變數分配記憶體,並設定預設初始值。 4)解析:把類中的符號引用轉換

Java 的定義對象引用

比對 對象的引用 類名 () web 變量名 初始 ble 擴展性 Java的核心思想萬物皆對象。 對象是對屬性(成員變量, 靜態屬性)和方法(函數, 動態屬性)的封裝 定義一個類 public class 類名{ 成

java載入——ClassLoader

web rac rgb 好的 全盤負責機制 安全 trac 字節 如何 Java的設計初衷是主要面向嵌入式領域,對於自己定義的一些類,考慮使用依需求載入原則。即在程序使用到時才載入類,節省內存消耗,這時就可以通過類載入器來動態載入。 假設你平時僅僅是做web開發,那應該

抽象(abstract class接口(interface)有什麽異同?

否則 繼承 默認 strong 什麽 成員 -s 實例 abstract 相同點: 1.抽象類和接口都不能被實例化,但可以定義抽象類和接口類型的引用。 2.一個類如果繼承了抽象類和接口,必須要對其中的抽象方法全部實現。(接口中方法默認的是public abstract修飾的

選擇:first-child:nth-child():first-of-type

head true http doctype 段落 元素 選擇 ont span x:first-child和x:nth-child(1)功能一樣,首先選中的是x元素,並且x元素必須是它父元素的第一個子元素,選擇器才成立,否則不能選中。其中x也可以是選擇器。由此看出nth-

Java載入 ClassLoader的解析

index html dir obj ble body 6.4 odin 普通 //參考 : http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 類載入器基本概念 類載