標籤:c++ 傳輸 無法 lang 模型 ffffff 不同 修改 home
1、什麼是類的載入
類的載入指的是將類的.class檔案中的位元據讀入到記憶體中,將其放在運行時資料區的方法區內,然後在堆區建立一個java.lang.Class對象,用來封裝類在方法區內的資料結構。類的載入的最終產品是位於堆區中的Class對象,Class對象封裝了類在方法區內的資料結構,並且向Java程式員提供了存取方法區內的資料結構的介面。
2、類的生命週期
其中類載入的過程包括了載入、驗證、準備、解析、初始化五個階段。在這五個階段中,載入、驗證、準備和初始化這四個階段發生的順序是確定的,而解析階段則不一定,它在某些情況下可以在初始化階段之後開始,這是為了支援Java語言的運行時綁定(也成為動態綁定或晚期綁定)。另外注意這裡的幾個階段是按順序開始,而不是按順序進行或完成,因為這些階段通常都是互相交叉地混合進行的,通常在一個階段執行的過程中調用或啟用另一個階段。
3、類載入器
站在Java虛擬機器的角度來講,只存在兩種不同的類載入器:啟動類載入器:它使用C++實現(這裡僅限於Hotspot,也就是JDK1.5之後預設的虛擬機器,有很多其他的虛擬機器是用Java語言實現的),是虛擬機器自身的一部分;所有其他的類載入器:這些類載入器都由Java語言實現,獨立於虛擬機器之外,並且全部繼承自抽象類別java.lang.ClassLoader,這些類載入器需要由啟動類載入器載入到記憶體中之後才能去載入其他的類。
站在Java開發人員的角度來看,類載入器可以大致劃分為以下三類:
啟動類載入器:Bootstrap ClassLoader,負責載入存放在JDK\jre\lib(JDK代表JDK的安裝目錄,下同)下,或被-Xbootclasspath參數指定的路徑中的,並且能被虛擬機器識別的類庫(如rt.jar,所有的java.*開頭的類均被Bootstrap ClassLoader載入)。啟動類載入器是無法被Java程式直接引用的。
擴充類載入器:Extension ClassLoader,該載入器由sun.misc.Launcher$ExtClassLoader實現,它負責載入DK\jre\lib\ext目錄中,或者由java.ext.dirs系統變數指定的路徑中的所有類庫(如javax.*開頭的類),開發人員可以直接使用擴充類載入器。
應用程式類載入器:Application ClassLoader,該類載入器由sun.misc.Launcher$AppClassLoader來實現,它負責載入使用者類路徑(ClassPath)所指定的類,開發人員可以直接使用該類載入器,如果應用程式中沒有自訂過自己的類載入器,一般情況下這個就是程式中預設的類載入器。
應用程式都是由這三種類載入器互相配合進行載入的,如果有必要,我們還可以加入自訂的類載入器。因為JVM內建的ClassLoader只是懂得從本地檔案系統載入標準的java class檔案,因此如果編寫了自己的ClassLoader,便可以做到如下幾點:
1)在執行非置信代碼之前,自動驗證數位簽章。
2)動態地建立符合使用者特定需要的定製化構建類。
3)從特定的場所取得java class,例如資料庫中和網路中。
JVM類載入機制
?全盤負責,當一個類載入器負責載入某個Class時,該Class所依賴的和引用的其他Class也將由該類載入器負責載入,除非顯示使用另外一個類載入器來載入
?父類委託,先讓父類載入器試圖載入該類,只有在父類載入器無法載入該類時才嘗試從自己的類路徑中載入該類
?緩衝機制,緩衝機制將會保證所有載入過的Class都會被緩衝,當程式中需要使用某個Class時,類載入器先從緩衝區尋找該Class,只有緩衝區不存在,系統才會讀取該類對應的位元據,並將其轉換成Class對象,存入緩衝區。這就是為什麼修改了Class後,必須重啟JVM,程式的修改才會生效
4、類的載入
類載入有三種方式:
1、命令列啟動應用時候由JVM初始化載入
2、通過Class.forName()方法動態載入
3、通過ClassLoader.loadClass()方法動態載入
5、雙親委派模型
雙親委派模型的工作流程是:如果一個類載入器收到了類載入的請求,它首先不會自己去嘗試載入這個類,而是把請求委託給父載入器去完成,依次向上,因此,所有的類載入請求最終都應該被傳遞到頂層的啟動類載入器中,只有當父載入器在它的搜尋範圍中沒有找到所需的類時,即無法完成該載入,子載入器才會嘗試自己去載入該類。
雙親委派機制:
1、當AppClassLoader載入一個class時,它首先不會自己去嘗試載入這個類,而是把類載入請求委派給父類載入器ExtClassLoader去完成。
2、當ExtClassLoader載入一個class時,它首先也不會自己去嘗試載入這個類,而是把類載入請求委派給BootStrapClassLoader去完成。
3、如果BootStrapClassLoader載入失敗(例如在$JAVA_HOME/jre/lib裡未尋找到該class),會使用ExtClassLoader來嘗試載入;
4、若ExtClassLoader也載入失敗,則會使用AppClassLoader來載入,如果AppClassLoader也載入失敗,則會報出異常ClassNotFoundException。
6、自訂類載入器
通常情況下,我們都是直接使用系統類別載入器。但是,有的時候,我們也需要自訂類載入器。比如應用是通過網路來傳輸 Java 類的位元組碼,為保證安全性,這些位元組碼經過了加密處理,這時系統類別載入器就無法對其進行載入,這樣則需要自訂類載入器來實現。自訂類載入器一般都是繼承自 ClassLoader 類,從上面對 loadClass 方法來分析來看,我們只需要重寫 findClass 方法即可。
自訂類載入器的核心在於對位元組碼檔案的擷取,如果是加密的位元組碼則需要在該類中對檔案進行解密。由於這裡只是示範,我並未對class檔案進行加密,因此沒有解密的過程。這裡有幾點需要注意:
1、這裡傳遞的檔案名稱需要是類的全限定性名稱,即com.paddx.test.classloading.Test格式的,因為 defineClass 方法是按這種格式進行處理的。
2、最好不要重寫loadClass方法,因為這樣容易破壞雙親委託模式。
3、這類Test 類本身可以被 AppClassLoader 類載入,因此我們不能把 com/paddx/test/classloading/Test.class 放在類路徑下。否則,由於雙親委託機制的存在,會直接導致該類由 AppClassLoader 載入,而不會通過我們自訂類載入器來載入。
http://www.cnblogs.com/ityouknow/p/5603287.html
Java類載入機制