JAVA反射機制深入學習(三)ClassLoader類裝載器介紹

接下來介紹下JAVA中非常重要的一個類ClassLoader(類裝載器)

類裝載器就是尋找類的字節碼文件並構造出類在JVM內部表示的對象組件。主要工作由ClassLoader及其子類負責,ClassLoader是一個重要的Java運行時系統組件,它負責在運行時查找和裝入Class字節碼文件。
在JAVA中java虛擬機把一個類裝入到java虛擬機當中需要經過以下的步驟:
1.裝載:查找和導入Class文件
2.鏈接:執行校驗,準備和解析步驟。
其中校驗主要是檢查載入class文件數據的正確性,而準備工作就是給類的靜態變量來分配存儲空間,解析則是將符號引用來轉變成直接引用。
3.初始化:對類的靜態變量、靜態代碼塊執行初始化工作
類文件被裝載並解析之後,在java虛擬機內將擁有一個對應的java.lang.class類描述對象。該類的對象實例則擁有指向這個類描述對象的引用。而類描述對象又擁有指向關聯ClassLoader的引用。
每一個類在java虛擬機當中都擁有一個對應的java.lang.class文件。他提供了類結構信息的描述,數組、枚舉、註解以及基本的java類型,甚至void都擁有對應的class屬性。Class沒有public的構造方法,class是在裝載類時由java虛擬機調用類裝載器中的defineClass方法來自動構造的。
JVM裝載類時使用全盤負責委託機制
全盤負責:當一個ClassLoader裝載一個類的時候,除非顯式的使用另一個ClassLoader,否則該類所依賴即引用的類也由這個ClassLoader來載入。
委託機制:先委託父裝載器尋找目標類,只有在找不到的情況下才從自己的類路徑中查找並裝載目標類。這一點是從安全角度來考慮的。
JVM在運行時會產生三個字節碼文件:根裝載器ExtClassLoader(擴展類裝載器AppClassLoader(系統類裝載器
根裝載器:不是ClassLoader的子類,由於他是使用C++來編寫的,因此在JAVA中看不到他。根裝載器來複制裝載jre的核心類庫,如jre目標下的rt.jar、charsets.jar等。
ExtClassLoader:是ClassLoader的子類,負責裝載jre擴展目錄ext中的jar類包
AppClassLoader:是ClassLoader的子類,負責裝載classpath路徑下的類
這三個裝載器之間存在着父子層級的關係:
根裝載器是ExtClassLoader的父裝載器,而ExtClassLoader是AppClassLoader的父裝載器。
在默認情況下使用AppClassLoader裝載應用程序的類。
接下來我們在程序中來驗證一下
public class ClassLoaderTest {

  public static void main(String[] args) {
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      System.out.println("current loader:"+loader);//打印當前類裝載器的信息
      System.out.println("parent loader:"+loader.getParent());//打印當前類裝載器的父類
      System.out.println("grandparent loader:"+loader.getParent().getParent());//打印當前類裝載器的祖父
      //注意:根裝載器在JAVA中訪問不到
  }
}
可以看到打印的結果
current loader:sun.misc.Launcher$AppClassLoader@4b67cf4d
parent loader:sun.misc.Launcher$ExtClassLoader@60e53b93
grandparent loader:null

在JAVA中ClassLoader是一個抽象類,主要位於java.lang包中。接下來主要介紹一下該類主要的接口方法。
1.    Class loadClass(String name)
其中name參數是指定類裝載器需要裝載類的名字,且必須使用全限定類名。
在初始化類之前,應考慮進行類解析的工作,但並不是所有的類都需要解析。
如果java虛擬機只需要知道該類是否存在或者找該該類的超類那麼就不需要進行解析。
2.    Class defineClass(String name, byte[]b, int off,int len)
這個方法是將類文件的字節數組來轉換爲java虛擬機內部的java.lang.class對象。字節數組可已從本地文件系統,遠程網站中進行獲取。而name爲字節數組對應的全限定名。
3.    Class findSystemClass(String name)
從本地文件系統來載入class文件,如果本地文件系統不存在該class文件,那麼他將會拋出ClassNotFoundException這個異常。這個方法是java虛擬機默認使用的機制。
4.    Class findLoadedClass(String name)
調用該方法來查看classloader是否以裝入到某個類當中,如果已經裝入則返回java.lang.class對象,否則返回null。
如果強行裝載已經存在的類,那麼將會拋出鏈接錯誤。
5.    ClassLoader getParent()
獲取類裝載器的父裝載器。除根裝載器之外,所有的類裝載器都有且僅有一個父裝載器。ExtClassLoader的父裝載器是根裝載器,因爲根裝載器非java編寫,所以返回null。
除了java虛擬機默認的三個裝載器之外,還允許自定義裝載器用來實現一些特殊的需求。


發佈了68 篇原創文章 · 獲贊 132 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章