類是如何載入的?

2023-01-28 12:00:35

在 Java 中,類載入的流程有一個專門的機制叫做「類載入機制」。類載入機制是指一個類在 Java 虛擬機器器(JVM)中的執行流程,它也是 Java 程式能夠正常執行的關鍵所在,那它的具體執行流程是啥?接下來我們一起來看。

流程概述

在 JVM 中,類載入會經歷以下 5 個階段:

  1. 載入階段(Loading)
  2. 驗證階段(Verification)
  3. 準備階段(Preparation)
  4. 解析階段(Resolution)
  5. 初始化階段(Initialization)

其中:驗證階段、準備階段和解析階段合起來又稱為連線階段,所以以上 5 個階段又可以劃分為 3 大類:

  1. 載入階段(Loading)
  2. 連線階段(Linking)
    1. 驗證階段(Verification)
    2. 準備階段(Preparation)
    3. 解析階段(Resolution)
  3. 初始化階段(Initialization)

具體分類如下圖所示:

這 3 大類、5 個流程的具體執行細節是這樣的。

1.載入階段

簡單來說,載入階段就是將類檔案載入到記憶體中的過程。在載入階段,JVM 需要完成以下 3 件事:

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

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

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

    2.連線階段

    連線階段又分為:驗證階段(Verification)、準備階段(Preparation)和解析階段(Resolution),具體執行的細節如下。

    2.1 驗證階段

    驗證階段也叫做校驗階段,它主要是用來驗證載入到記憶體中的類是否是安全合規的檔案,驗證的主要動作大概有以下幾個(當然,以下細節如果實在記不住也沒關係):

  • 檔案格式校驗包括常數池中的常數型別、Class 檔案的各個部分是否被刪除或被追加了其他資訊等;

  • 後設資料校驗包括父類別正確性校驗(檢查父類別是否有被 final 修飾)、抽象類校驗等;

  • 位元組碼校驗,此步驟最為關鍵和複雜,主要用於校驗程式中的語意是否合法且符合邏輯;

  • 符號參照校驗,對類自身以外比如常數池中的各種符號參照的資訊進行匹配性校驗。

    2.2 準備階段

    準備階段就開始給類中的靜態變數設定預設值了,注意這裡不是給靜態變數設定初始值,而是設定預設值,二者還是有很大區別的。
    舉個例子,比如程式碼中寫的內容是:

    public static int number = 10;

那麼此時是給 number 變數設定的 int 值是預設值 0,而非初始值 10。

2.3 解析階段

解析階段就是將常數池中的符號參照更換成直接參照了,所謂的符號參照是指以一組符號來描述所參照的目標,符號可以是任何形式的字面量,只要使用時能無歧義地定位到目標即可;而直接參照是可以直接指向目標的指標、相對偏移量或者是一個能間接定位到目標的控制程式碼。
符號參照和直接參照有一個重要的區別:使用符號參照時被參照的目標不一定已經載入到記憶體中;而使用直接參照時,參照的目標必定已經存在虛擬機器器的記憶體中了。

3.初始化階段

初始化階段,Java 虛擬機器器真正開始執行類中編寫的 Java 程式程式碼,將主導權移交給應用程式。到這一步驟之後,類的載入過程就算正式完成了,此時會給靜態變數設定初始值,並執行靜態程式碼塊的內容。

總結

類載入流程總共分為 3 大類,5 個主要流程:

  1. 載入階段(Loading):將類檔案載入到記憶體。
  2. 連線階段(Linking)
    1. 驗證階段(Verification):類檔案安全性效驗。
    2. 準備階段(Preparation):給靜態變數設定預設值。
    3. 解析階段(Resolution):將符號參照轉換為直接參照。
  3. 初始化階段(Initialization):執行靜態程式碼塊和給靜態變數設定初始值。

本文已收錄到 Gitee 開源倉庫《Java 面試指南》,其中包含的內容有:Redis、JVM、並行、並行、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、設計模式、訊息佇列等模組。Java 面試有它就夠了,點選檢視詳情:interview: 400+ 道 Java 常見面試題和解析,持續更新中......