1. 程式人生 > >03 Java 虛擬機是如何加載 Java 類的

03 Java 虛擬機是如何加載 Java 類的

接口 靜態方法 只需要 元空間 圖片 虛方法 擴展 lan 轉發

Java 引用類型

Java 中的引用類型細分為四種:類,接口,數組類和泛型參數。

因為泛型參數會在編譯過程中被擦除,所以 Java 虛擬機實際上只有前三種。數組類是由 Java 虛擬機直接生成的,其他兩種則有對應的字節流。

無論是數組類還是其他兩種類型,Java 虛擬機都需要對其進行鏈接和初始化。

加載

加載就是查找字節流,然後據此創建類的過程。數組類由 Java 虛擬機直接生成,其他類則需要 Java 虛擬機借助類加載器來完成查找字節流的過程。

類加載器有很多種,除了啟動類加載器以外,其他的類加載器都是 java.lang.ClassLoader 的子類,因此有對應的 Java 對象。這些類加載器都需要先由其他類加載器比如說啟動類加載器加載到 Java 虛擬機中,方能執行類加載。

雙親委派機制:每當一個類加載器接收到加載請求時,它會先將請求轉發給父類加載器。如果父類加載器沒有找到所請求的類的情況下,該類加載器才會嘗試去加載。

在 Java 9 之前,啟動類加載器負責加載最基礎最重要的類。除了啟動類加載器之外,還有擴展類加載器和應用類加載器,均由 Java 核心類庫提供。

擴展類加載器的父類加載器是啟動類加載器。它負責加載相對次要但通用的類。

應用類加載器的父類加載器是擴展類加載器。它負責加載應用程序路徑下的類。

Java 9 中擴展類加載器被改名為平臺類加載器。Java SE 中除了少數幾個關鍵模塊是由啟動類加載器加載之外,其他模塊均由平臺類加載器所加載。

在 Java 虛擬機中,類的唯一性是由類加載器實例以及類的全名一同確定的。

鏈接

鏈接是指將創建成的類合並至 Java 虛擬機中,使之能夠執行的過程。它可以分為:驗證,準備和解析三個階段。

驗證階段:確保加載類能夠滿足 Java 虛擬機的約束條件。通常情況下,Java 編譯器生成的類文件必然滿足 Java 虛擬機的約束條件。(除了字節碼註入)

準備階段:為被加載類的靜態字段分配內存,初始化則會在初始化階段進行。部分 Java 虛擬機還會在此階段構造其他跟類層次相關的數據結構,比如說用來實現虛方法的動態綁定的方法表。

在 class 文件被加載至 Java 虛擬機之前,這個類無法知道其他類以及其方法和字段所對應的具體地址,甚至不知道自己方法和字段的地址。當需要引用這些成員時,Java 編譯器會生成一個符號引用,在運行階段這些符號引用會定位到具體目標上。

解析階段就是將這些符號引用解析成為實際引用。

Java 虛擬機規定:如果某些字節碼使用了符號引用,那麽在執行這些字節碼之前,需要完成對這些符號引用的解析。也就是說,在鏈接過程中不要求一定解析完成。

初始化

在 Java 代碼中,初始化一個靜態字段,可以聲明時賦值,也可以在靜態代碼塊中賦值。

如果被賦值的靜態字段被 final 修飾,並且它是基本類型或者字符串時,那麽該字段便會被 Java 編譯器標記成常量值,其初始化直接由 Java 虛擬機完成。除此之外的直接復制操作每一集靜態代碼塊中的代碼,都會被 Java 編譯器置於同一方法中,命名為

類的初始化,就是為標記常量的字段賦值,以及執行

舉例一下情況會觸發類的初始化:
1:虛擬機啟動時,初始化用戶指定的主類。
2:遇到 new 指令時,初始化 new 指令的目標類。
3:當遇到調用靜態方法的指令時,初始化該靜態方法所在的類。
4:當遇到訪問靜態字段的指令時,初始化該靜態方法所在的類。
5:子類的初始化會觸發父類的初始化。
6:如果一個接口定義了 default 方法,那麽實現該接口的類初始化時,會觸發接口的初始化。
7:使用反射 API 對某個類進行反射調用時,初始化該類。

問答

Q:新建類,和新建類的數組,初始化過程

新建類的時候,需要加載,鏈接和初始化。新建類的數組的時候,由於並沒有使用類,所以只需要加載該類。如果需要使用該類了,在執行類的鏈接和初始化。

Q:類的初始化和實例的初始化區別,初始化後的類存儲在什麽地方

類的初始化只有一次,通過類的加載鏈接生成對應的數據結構,存儲在元空間。實例的初始化可以有多次。

Q:類中的靜態字段,如果沒有被 JVM 標記為常量,那麽如何分配內存

加載類的過程,都會分配內存,只是初始化的時候不一樣:一個是在 JVM 中直接復制,一個是在 clinit 方法中復制。

Q clinit 執行時的鎖,是什麽鎖,跟 synchronized 一樣嗎

clinit 執行時的鎖是虛擬機內部鎖,和 synchronized 不一樣。

總結

本文創作靈感來源於 極客時間 鄭雨迪老師的《深入拆解 Java 虛擬機》課程,通過課後反思以及借鑒各位學友的發言總結,現整理出自己的知識架構,以便日後溫故知新,查漏補缺。

關註本人公眾號,第一時間獲取最新文章發布,每日更新一篇技術文章。

技術分享圖片

03 Java 虛擬機是如何加載 Java 類的