天天看點

Java類加載器學習1——類加載器的基本概念

一、程式使用java類的運作順序

當程式主動使用某個類的時候,若該類還未被加載至記憶體中,系統會通過加載,連接配接,初始化三個步驟對類進行初始化,有事也把這三個步驟稱為類加載或者類的初始化。

1 類的加載

将被編譯的.java而成為.class位元組碼讀入jvm記憶體并為之建立一個java.lang.class對象,也就是說當程式中使用任何類的時候系統都會為之建立一個java.lang.class對象。類的加載由類加載器完成,類加載器通常有jvm提供,我們稱jvm提供的類加載器為系統類加載器。當然實際的情況可能更加複雜比如java位元組代碼可能是通過工具動态生成的,也可能是通過網絡下載下傳的。

2 類的連接配接

當生成一個對應的.class對象後,接着會進入連接配接階段,會将類的二進制資料合并到jre中,該階段又認為驗證,準備,解析三個階段。

3 類的初始化

由jvm負責對類進行初始化,主要就是對靜态屬性進行初始化。(1)聲明靜态屬性時指定初始值 (2)使用靜态初始化塊為靜态屬性指定初始值。

本文主要講解第一個步驟——類的加載。

二、類的加載的基本概念

基本上所有的類加載器都是java.lang.classloader類的一個執行個體。java.lang.classloader類的基本職責就是根據一個指定的類的名稱,找到或者生成其對應的位元組代碼,然後從這些位元組代碼中定義出一個java類,即java.lang.class類的一個執行個體。除此之外classloader還負責加載java應用所需的資源,如圖像檔案和配置檔案等。不過本文隻讨論其加載類的功能。為了完成加載類的這個職責,classloader提供了一系列的方法。jdk中幾個比較重要的方法:

getparent()

傳回委托的父類加載器

loadclass(string name)

加載名稱為name的類,傳回的結果是java.lang.class類的執行個體

findclass(string name)

查找名稱為name的類,傳回的結果是java.lang.class類的執行個體

findloadedclass(string name)

查找名稱為 name的已經被加載過的類,傳回的結果是 java.lang.class類的執行個體

defineclass(string name, byte[] b, int off, int len)

把位元組數組b中的内容轉換成java類,傳回的結果是java.lang.class類的執行個體。此方法被聲明為final

resolveclass(class<?> c)

連結指定的java類 

上述name是二進制名,按照《java language specification》的定義,任何作為string類型參數傳遞給classloader中方法的類名稱都必須是一個二進制名稱。 有效類名稱的示例包括:

"java.lang.string"

"javax.swing.jspinner$defaulteditor"

"java.security.keystore$builder$filebuilder$1"

"java.net.urlclassloader$3$1"

三、類加載器的分類

java 中的類加載器大緻可以分成兩類,一類是系統(jvm)提供的,一類是由java應用開發人員編寫的。

系統提供的類加載器主要有下面三個:

引導類加載器(bootstrap class loader)

用來加載 java 的核心庫,是用原生代碼(c++)來實作的,并不繼承自java.lang.classloader。

擴充類加載器(extensions class loader)

用來加載java的擴充庫。java虛拟機的實作會提供一個擴充庫目錄。該類加載器在此目錄裡面查找并加載 java 類。

系統類加載器(system class loader)

根據java應用的類路徑(classpath)來加載java類。一般來說java應用的類都是由它來完成加載的。可以通過 classloader.getsystemclassloader()來擷取它。

除了系統提供的類加載器外開發人員可以通過繼承java.lang.classloader類的方式實作自己的類加載器,以滿足一些特殊的需求。

除了引導類加載器外,所有的類加載器都有一個父類加載器。通過getparent()方法可以得到。對于系統提供的類加載器來說,系統類加載器的父類加載器是擴充類加載器,而擴充類加載器的父類加載器是引導類加載器;對于開發人員編寫的類加載器來說,其父類加載器是加載此類加載器java類的類加載器。因為類加載器java類如同其它的java類一樣,也要由類加載器來加載的。一般來說開發人員編寫的類加載器的父類加載器是系統類加載器。類加載器通過這種方式組織起來,形成樹狀結構。樹的根節點就是引導類加載器。看一張傳智播客的圖

Java類加載器學習1——類加載器的基本概念

看一段測試代碼 

四、類加載器的父類委托機制

java的類加載器自從jdk1.2開始便引入了一條機制,叫做父類委托機制。

一個類需要被加載的時候,jvm先會調用他的父類加載器進行加載。如果父類加載器加載不了,再使用其子類進行加載。當然這類所說的父類加載器,不一定他們之間是繼承的關系,有可能僅僅是包裝的關系。不能片面了解。

當java虛拟機要加載類時,如果上一級加載器可以加載則交由上一級加載,如使用者編寫一個java.lang.system類,交給appclassloader加載—>extclassloader加載—>bootstrap加載,而rt.jar這個包中本來就有一個system類,是以使用者編寫的system類不起作用。如果bootstrap加載不到,則将由extclassloader加載—>appclassloader加載,最後還加載不了就傳回classnotfoundexception異常,不會交給發起請求的加載器的子加載器。

java之是以出現這條機制,因為是處于安全性考慮。害怕使用者自己定義class檔案然後自己寫一個類加載器來加載原本應該是jvm自己加載的類。這樣會是jvm虛拟機混亂或者說會影響到使用者的安全。

參考位址

<a target="_blank" href="http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#major5">http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#major5</a>

<a target="_blank" href="http://blog.csdn.net/a352193394/article/details/7343385">http://blog.csdn.net/a352193394/article/details/7343385</a>