1. 程式人生 > >深入理解Java虛擬機器 類載入子系統2

深入理解Java虛擬機器 類載入子系統2

與C/C++那些需要在編譯器期進行連線工作的語言不同,Java類的載入、連線和初始化都是在程式執行時完成的,只有在類被需要的時候才進行動態載入。

1)JVM何時載入類?
有且只有以下5種情況:

  • 建立新物件(new)、設定/讀取static欄位(putstatic/getstatic)或呼叫靜態方法(invokestatic)這四條指令時,如果該類沒有初始化,則初始化。
  • 使用java.lang.reflect包得方法進行反射呼叫的時候,如果該類沒有初始化,則初始化。
  • 當初始化一個類時,父類沒有初始化,則先初始化父類。
  • 當虛擬機器啟動,需要執行main()的主類,JVM首先初始化該類。
  • JDK 1.7的動態語言支援時,如果java.lang.invoke.MethodHandle例項最後的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic的方法控制代碼,並且這個方法控制代碼所對應的類沒有進行過初始化,則初始化。

2)如何載入類?
類載入過程包括載入(Loading)、連結(Linking)和初始化(Initialization)三個過程。

這裡寫圖片描述

載入(Loading)

  • 其中“根據全限定名獲取位元組流”的過程,可以有系統提供的類載入器完成,也可以由使用者自定義類載入器。
  • 對於HotSpot,Class物件雖然是物件,但仍然存放在方法區中。


連結-準備

  • 該階段值正式在方法區為類變數分配記憶體初始化類變數,
    public static int value = 123
    在準備階段初始化零值,而非123。初始化123的過程在初始化階段完成。


連結-解析

  • 將常量池中的符號引用替換成直接引用。其中對於非虛方法,在類載入階段就可以確定呼叫的版本,因此可以在此階段直接解析為直接引用;為對於虛方法(即支援多型),無法在此階段確定呼叫版本,虛方法的符號引用需等到程式執行到該符號引用的位元組碼時才能解析為直接引用。
  • 解析動作主要針對類或介面、欄位、類方法、介面方法、方法型別、方法型別等符號引用。
  • 執行讀寫欄位(getstatic、putstatic、getfield、putfield)、instanceof、方法呼叫(iinvokestatic、invokespecial、invokevirtual、invokedynamic)、new等操作符號引用的位元組碼之前,需要先進行符號引用解析。


初始化(Initialization)

  • 執行類構造器<clinit>:自動收集static變數和static{}塊,按原檔案出席西安的順序執行初始化。
  • <clinit>由編譯器自動生成,如果沒有static變數和static{}塊,就不會生成。
類載入器(ClassLoader)

“根據全限定名獲取位元組流”的過程,即類載入器的工作。JVM通過ClassLoader和類本身共同判斷兩個Class是否相同。即使兩個類屬於同一個Class檔案,如果載入他們的ClassLoader不同,那麼他們將被視為不同的類。

對於核心庫類如java.lang.Object,如果使用者程式自己編寫了一個名為java.lang.Object的類,並使用自定義類載入器載入,那麼將導致程式中存在多個java.lang.Object類,程式會十分混亂,為了保證程式載入的都是核心庫類的java.lang.Object,引入了雙親委託模型

雙親委託模型
雙親委託模式的思路是:當一個類載入器收到了類載入請求,它會首先將該請求委託給父類載入器去完成,並且每一個層次類載入器都是如此,只有父類載入器無法完成載入請求時,子類載入器才嘗試自己去載入。

啟動類載入器(Bootstrap Class Loader) 基本由原生代碼實現,用於載入Java最基本API如rt.jar。只用於載入<JAVA_HOME>/lib目錄下具有高可靠性的類。classLoader=null即表示啟動類載入器。

擴充套件類載入器(Extension Class Loader) 載入Java extension APIs,如security extension功能類。載入位於<JAVA_HOME>/lib/ext路徑的類。

系統類載入器(System Class Loader) 程式預設類載入器,載入使用者類路徑classpath的類。

使用者自定義載入器(User Defined Class Loaders) 自定義類載入器,如Tomecat對每一個Web應用程式對應一個WebApp類載入器,每個JSP檔案對應一個Jsp類載入器。