1. 程式人生 > >java載入class檔案(類載入機制)

java載入class檔案(類載入機制)

一概述:在編譯期,所有的*.java檔案被編譯成.class檔案。在執行期,class檔案只有被載入到jvm記憶體中才能執行。這個裝載工作是由類裝載器完成的。實質就是把class檔案從硬碟讀取到記憶體中,並對資料進行校驗,轉化解析和初始化,最終形成可以被jvm直接使用的java型別。

二類載入全過程


                                                                                            類的生命週期

1、載入

  1)通過一個類的全限定名來獲取定義此類的的二進位制位元組流

  2)將這個位元組流所代表的靜態儲存結構轉化為方法區執行時的資料結構

  3)在記憶體中生成一個java.lang.Class物件,作為方法區這個類的各種資料的訪問入口。

2、 驗證:確保Class檔案中的位元組流中的包含資訊符合jvm的要求,並且不會虛擬機器自身的安全。

3、準備:在方法區給靜態的類變數分配記憶體,並設定初始值。例項變數(未被static修飾的類變數)將會在物件例項化時,隨物件一起分配到java堆中。

4、解析:將符號引用轉成直接引用。其中解析階段可以在初始化後再開始,這是為了支援JAVA語言執行時繫結(動態繫結或晚繫結,例如多型)。

5、初始化:對靜態變數和靜態程式碼塊執行初始化工作。

三類載入時機

  1、 jvm規範並沒有強制約束類載入過程的第一個階段,具體實現由jvm自由把握。但是有且只有5種情況必須對類進行初始化(而載入、驗證、準備自然需要在此之前開始)。這裡簡單說說最常見的java程式碼場景是:使用new關鍵字例項化物件的時候,讀取或設定類的靜態欄位(被final修飾、已在編譯期把結果放入常量池的靜態欄位除外)的時候,以及呼叫一個類的靜態方法的時候。

  2、類載入的動態性體現

  一個應用程式是由n多個類組成的。Java程式啟動時,先把基礎的類載入到jvm,其他類等到需要用時,再載入到jvm。這樣做的好處主要是為了節省記憶體的開銷;而用時再載入也是java動態性的一種體現。

四類載入器是如何協調,載入類的

1、類分為三種:系統類,擴充套件類,應用類(程式設計師自定義的類)。

2、類裝載器:本質上也是一種類。層次結構如下,

  Bootstrap classloader  - 負責載入系統類
            |
          - - ExtClassLoader  - 負責載入擴充套件類
                    |


                   - - AppClassLoader  - 負責載入應用類

bootstrap classloader是由c++寫的,所以邏輯上不存在bootstrap classloader的類實體,當用getParent()列印輸出bootstrap classloader,結果為null。

3、載入流程:當執行一個程式,jvm啟動,執行bootstrap classloader,該ClassLoader載入java核心API,然後呼叫ExtClassLoader載入擴充套件API,最後APPClassLoader載入Classpath目錄下定義的Class,這就是一個程式最基本的載入流程。類的載入過程使用了一種父類委託模式。當嘗試載入一個類時,會先檢查這個類是否已經載入。如果沒有載入,先獲取父類裝載器搜尋路徑進行裝載,如果parent找不到或parent不存在,就依照自己的裝載器進行載入類。採取這種模式的原因有兩個。1當父類已經載入了該類的時候,就沒有必要子類ClassLoader再載入一次;2如果不使用父類委託模式,那麼可以隨時使用自定義的String來動態代替Java核心API中定義的型別,存在非常大的安全隱患。下面是ClassLoader中的一段程式碼,

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
       synchronized (getClassLoadingLock(name)){
           //首先檢查該name指定的class是否被載入過
           Class c = findLoadedClass(name);
           if (c == null) {
               try {
                   if (parent != null) {
                       //如果parent不為null,則呼叫parent的loadClass進行載入
                       c = parent.loadClass(name, false);
                   } else {
                       //如果parent為null,則呼叫bootstrap ClassLoader進行載入
                       c = findBootstrapClassOrNull(name);
                   }
               }catch (ClassNotFoundException e) {
                     // ClassNotFoundException thrown if class not found
                     // from the non-null parent class loader
               }
               if (c == null) {
                   // If still not found, then invoke findClass in order
                   // to find the class.
                   //如果仍然無法載入成功,則呼叫自身的findClass進行載入
                   c = findClass(name);
                }
	            //帶解析裝入類
	            if (resolve) {
	               resolveClass(c);
	            }
	            return c;
           }
      }
}