類裝載器工做機制
類裝載器就是尋找類的節碼文件並構造出類在JVM內部表示對象的組件。在Java中,類裝載器把一個類裝入JVM中,要通過如下步驟: java
[2.]連接:執行校驗、準備和解析步驟,其中解析步驟是能夠選擇的:
[2.1]校驗:檢查載入Class文件數據的正確性;
[3.]3.初始化:對類的靜態變量、靜態代碼塊執行初始化工做。
類裝載工做由ClassLoader及其子類負責,ClassLoader是一個重要的Java運行時系統組件,它負責在運行時查找和裝入Class字節碼文件。JVM在運行時會產生三個ClassLoader:根裝載器、ExtClassLoader(擴展類裝載器)和AppClassLoader(系統類裝載器)。其中,根裝載器不是ClassLoader的子類,它使用C++編寫,所以咱們在Java中看不到它,根裝載器負責裝載JRE的核心類庫,如JRE目標下的rt.jar、charsets.jar等。ExtClassLoader和AppClassLoader都是ClassLoader的子類。其中ExtClassLoader負責裝載JRE擴展目錄ext中的JAR類包;AppClassLoader負責裝載Classpath路徑下的類包。
這三個類裝載器之間存在父子層級關係,即根裝載器是ExtClassLoader的父裝載器,ExtClassLoader是AppClassLoader的父裝載器。默認狀況下,使用AppClassLoader裝載應用程序的類,咱們能夠作一個實驗:
代碼清單3-11 ClassLoaderTest 編程
運行以上代碼,在控制檯上將打出如下信息: 數組
引用
current loader:sun.misc.Launcher$AppClassLoader@131f71a
parent loader:sun.misc.Launcher$ExtClassLoader@15601ea
//①根裝載器在Java中訪問不到,因此返回null
grandparent loader:null
經過以上的輸出信息,咱們知道當前的ClassLoader是AppClassLoader,父ClassLoader是ExtClassLoader,祖父ClassLoader是根類裝載器,由於在Java中沒法得到它的句柄,因此僅返回null。
JVM裝載類時使用「全盤負責委託機制」,「全盤負責」是指當一個ClassLoader裝載一個類的時,除非顯式地使用另外一個ClassLoader,該類所依賴及引用的類也由這個ClassLoader載入;「委託機制」是指先委託父裝載器尋找目標類,只有在找不到的狀況下才從本身的類路徑中查找並裝載目標類。這一點是從安全角度考慮的,試想若是有人編寫了一個惡意的基礎類(如java.lang.String)並裝載到JVM中將會引發多麼可怕的後果。可是因爲有了「全盤負責委託機制」,java.lang.String永遠是由根裝載器來裝載的,這樣就避免了上述事件的發生。
ClassLoader重要方法
在Java中,ClassLoader是一個抽象類,位於java.lang包中。下面對該類的一些重要接口方法進行介紹: 安全
- Class loadClass(String name)
name參數指定類裝載器須要裝載類的名字,必須使用全限定類名,如com.baobaotao. beans.Car。該方法有一個重載方法loadClass(String name ,boolean resolve),resolve參數告訴類裝載器是否須要解析該類。在初始化類以前,應考慮進行類解析的工做,但並非全部的類都須要解析,若是JVM只須要知道該類是否存在或找出該類的超類,那麼就不須要進行解析。
- Class defineClass(String name, byte[] b, int off, int len)
將類文件的字節數組轉換成JVM內部的java.lang.Class對象。字節數組能夠從本地文件系統、遠程網絡獲取。name爲字節數組對應的全限定類名。
- Class findSystemClass(String name)
從本地文件系統載入Class文件,若是本地文件系統不存在該Class文件,將拋出ClassNotFoundException異常。該方法是JVM默認使用的裝載機制。
- Class findLoadedClass(String name)
調用該方法來查看ClassLoader是否已裝入某個類。若是已裝入,那麼返回java.lang.Class對象,不然返回null。若是強行裝載已存在的類,將會拋出連接錯誤。
- ClassLoader getParent()
獲取類裝載器的父裝載器,除根裝載器外,全部的類裝載器都有且僅有一個父裝載器,ExtClassLoader的父裝載器是根裝載器,由於根裝載器非Java編寫,因此沒法得到,將返回null。
除JVM默認的三個ClassLoader之外,能夠編寫本身的第三方類裝載器,以實現一些特殊的需求。類文件被裝載並解析後,在JVM內將擁有一個對應的java.lang.Class類描述對象,該類的實例都擁有指向這個類描述對象的引用,而類描述對象又擁有指向關聯ClassLoader的引用,如圖3-4所示。
每個類在JVM中都擁有一個對應的java.lang.Class對象,它提供了類結構信息的描述。數組、枚舉、註解以及基本Java類型(如int、double等),甚至void都擁有對應的Class對象。Class沒有public的構造方法。Class對象是在裝載類時由JVM經過調用類裝載器中的defineClass()方法自動構造的。
Java反射機制
Class反射對象描述類語義結構,能夠從Class對象中獲取構造函數、成員變量、方法類等類元素的反射對象,並以編程的方式經過這些反射對象對目標類對象進行操做。這些反射對象類在java.reflect包中定義,下面是最主要的三個反射類: 網絡
- Constructor:類的構造函數反射類,經過Class#getConstructors()方法能夠得到類的全部構造函數反射對象數組。在JDK5.0中,還能夠經過getConstructor(Class... parameterTypes)獲取擁有特定入參的構造函數反射對象。Constructor的一個主要方法是newInstance(Object[] initargs),經過該方法能夠建立一個對象類的實例,至關於new關鍵字。在JDK5.0中該方法演化爲更爲靈活的形式:newInstance (Object... initargs)。
- Method:類方法的反射類,經過Class#getDeclaredMethods()方法能夠獲取類的全部方法反射類對象數組Method[]。在JDK5.0中能夠經過getDeclaredMethod(String name, Class... parameterTypes)獲取特定簽名的方法,name爲方法名;Class...爲方法入參類型列表。Method最主要的方法是invoke(Object obj, Object[] args),obj表示操做的目標對象;args爲方法入參,代碼清單3 10③處演示了這個反射類的使用方法。在JDK 5.0中,該方法的形式調整爲invoke(Object obj, Object... args)。此外,Method還有不少用於獲取類方法更多信息的方法:
1)Class getReturnType():獲取方法的返回值類型;
2)Class[] getParameterTypes():獲取方法的入參類型數組;
3)Class[] getExceptionTypes():獲取方法的異常類型數組;
4)Annotation[][] getParameterAnnotations():獲取方法的註解信息,JDK 5.0中的新方法;
- Field:類的成員變量的反射類,經過Class#getDeclaredFields()方法能夠獲取類的成員變量反射對象數組,經過Class#getDeclaredField(String name)則可獲取某個特定名稱的成員變量反射對象。Field類最主要的方法是set(Object obj, Object value),obj表示操做的目標對象,經過value爲目標對象的成員變量設置值。若是成員變量爲基礎類型,用戶能夠使用Field類中提供的帶類型名的值設置方法,如setBoolean(Object obj, boolean value)、setInt(Object obj, int value)等。
此外,Java還爲包提供了Package反射類,在JDK 5.0中還爲註解提供了AnnotatedElement反射類。總之,Java的反射體系保證了能夠經過程序化的方式訪問目標類中全部的元素,對於private或protected的成員變量和方法,只要JVM的安全機制容許,也能夠經過反射進行調用,請看下面的例子:
代碼清單3-12 PrivateCarReflect 函數
color變量和drive()方法都是私有的,經過類實例變量沒法在外部訪問私有變量、調用私有方法的,但經過反射機制卻能夠繞過這個限制:
代碼清單3-13 PrivateCarReflect spa
運行該類,打印出如下信息: code
引用
drive private car! the color is:紅色
在訪問private、protected成員變量和方法時必須經過setAccessible(boolean access)方法取消Java語言檢查,不然將拋出IllegalAccessException。若是JVM的安全管理器設置了相應的安全機制,調用該方法將拋出SecurityException。 對象