1. 程式人生 > >深入java虛擬機器(六)——類載入的父親委託機制

深入java虛擬機器(六)——類載入的父親委託機制

          在前面兩篇部落格中我們簡單介紹了類載入器的基礎和類的生命週期的基礎內容,今天我們來繼續深入的來看一下java的類載入器的詳細內容。我們都知道。類載入器用來把類載入到java虛擬機器。從JDK2.0開始,類的載入過程採用父親委託機制。JVMClassLoader採用的是樹形結構,除了根類載入器以外,每個ClassLoader都會有且僅有一個父類載入器,使用者自定義的ClassLoader預設的父類載入器是系統類載入器,當然你可以自己指定需要用個ClassLoader的例項,我們來看他們的父子關係:


                                                       



      父類委託機制中,當一個java程式請求載入器loader1載入Hello類時,loader1首先委託自己的父親載入器載入hello類,若父親載入器能載入,則由附加器完成載入人物,否則才由載入器loader1本身載入Hello類。下面我們來再次看一下java虛擬機器自帶的幾個載入器:


                     



       除了java

虛擬機器自帶的載入器之外,我們使用者自己也可以自定義自己的類載入器,根據自己的需要。。Java提供了抽象類java.lang.ClassLoder,所有使用者自定義的類載入器都要繼承這個classloader類。

 

     注:載入器之間的父子關係實際上指的是載入器物件之間的包裝關係,而不是類之間的繼承關係。一對父子載入器可能是同一個載入器類的兩個例項,也可能不是。在子載入器物件中包裝了一個父載入器物件.當生成一個自定義的類載入器例項時,如果沒有指定它的父載入器,那麼系統類載入器就將成為該類載入器的父載入器。如果在構造方法中指定父類載入器那麼父類載入器就是指定的載入器。證明如下:

                   


ClassLoader loader1 = new MyClassLoader();
//引數loader1將作為loader2的父載入器
ClassLoader loader2 = new MyClassLoader(loader1);


 當Java虛擬機器要載入一個類時,到底該派哪個類載入器去載入呢 ?我們看下圖:

                                                                     

        Loader1loader2是我們自己定義的兩個類載入器,loader1loader2是父子關係。現在我們想讓loader2這個類載入器載入我們自己寫的一個Sample類:loader2.loadclass(“sample”),我們來分析一下看看到底應該用哪一個類載入器去載入。當這段程式碼被執行時,loader2首先到自己的名稱空間去查詢Sample類是否已經被載入,如果被載入就直接返回這個類的class物件的引用。如果Sample類還沒有被載入,loader2首先請求loader1代為載入,loader1再請求系統類載入器代為載入,系統類載入器再請求擴充套件類載入器,擴充套件類載入器再請求根類載入器,若根類載入器和擴充套件類載入器都不能載入,則系統類載入器嘗試載入,若能載入,則將Sample類所對應的Class物件的引用返回給loader1loader1在將引用返回給loader2,從而成功將Sample類載入到虛擬機器。若系統類載入器不能載入Sample類,則loader1嘗試載入Sample了哦,若loader1不能載入,則loader2嘗試,若所有的類載入都不能載入,則丟擲ClassNotFoundException異常。


定義類載入器:如果某個類載入器能夠載入一個類,那麼該類載入器就稱作:定義類載入器;定義類載入器及其所有子載入器都稱作:初始類載入器

      父委託機制的優點就是能夠提高軟體系統的安全性。因為在詞機制下,使用者自定義的類載入器不可能載入本應該由父載入器載入的可靠類,從而防止不可靠的惡意程式碼代替由父類載入器載入的可靠類,從而防止不可靠的甚至惡意的程式碼代替由父類載入器載入的可靠程式碼。如,java.lang.Object類總是由根類載入器載入的,其他任何使用者自定義的類載入器都不可能載入含有惡意程式碼的java.lang.Object類。 


     名稱空間,其實這裡所說的名稱空間就是我們java中常用的package,每個類載入器都有自己的名稱空間,名稱空間由該載入器及所有父載入器所載入的類的組成。在同一個名稱空間中,不會出現類的完整名字(包括類的包名)相同的兩個雷;在不同的名稱空間中,有可能會出現類的完整名字(包括類的包名)相同的兩個類。


  由同一類載入器載入的屬於相同包的類組成了執行時包。決定兩個類是不是屬於同一個執行時包,不僅要看他們的包名稱是否相同,還要看定義類載入器是否相同。只有屬於同一執行時包的類之間才能相互訪問可見(預設訪問級別)的類和成員。假設使用者自定義了一個類java.lang.TestCase並由用於自定義的類載入器載入,由於java.lang.TestCase和核心類庫java.lang.*由不同的類載入器載入,他們屬於不同的執行時包,所以java.lang.TestCase不能訪問核心庫java.lang包中的包可見成員。



參考資料:北京張龍老師免費培訓視訊《類載入器的父親委託機制深度詳解》


------------------------------------------------------------------------------------------------------------

《Java程式設計師由笨鳥到菜鳥》電子版書正式釋出,歡迎大家下載


http://blog.csdn.net/csh624366188/article/details/7999247