Java基本知識:Java虛擬機器是如何載入類的
Java虛擬機器類載入的先後順序是載入,連結以及初始化三個操作。
引用型別在Java虛擬機器中認為有三種,介面,類與陣列類。
資料類是Java虛擬機器直接生成的,其他兩種則有對應的位元組流。
位元組流最常見的形式是Java編譯器生成的class檔案。除此之外可以在程式內部直接生成。不同形式的位元組流都會被載入到虛擬機器哄,稱為類或者介面。
載入
載入:查詢位元組流,並根據此建立類的過程。陣列類能被Java虛擬機器直接接受,但是介面與類需要藉助類載入器來完成查詢位元組流的操作。
除了啟動類載入器之外,其他的類載入器都是ClassLoader下子類。
需要先把啟動類載入器載入到虛擬上才能載入其他型別的類載入器。
-
Java9之前啟動類載入器負責載入最為基礎,最為重要的類。
擴充套件類載入器的父類載入器是啟動類載入器。負責載入相對次要,但又通用的類、存放在lib/ext下面的jar包中的類。
應用類載入器的父類載入器則是擴充套件類載入器。負責載入應用程式路徑下的類。系統變數,或者環境變數,虛擬機器引數-cp/-classpath,三者下的類。。 -
Java9 之後引入模組系統,載入器進行了修改。
擴充套件類載入器改為平臺類載入器,除了少數幾個關鍵模組是由啟動類載入載入之外,其他模組都是有平臺類載入器載入。
可以引入自定義的載入器,實現定製化的方式。
類的唯一性是由類載入器與類的全名兩者一同確定的。
連結
指將建立成的類合併至Java虛擬機器中,是指能夠執行,分為驗證、準備、以及解析三個階段。
- 驗證:確保載入類能夠滿足Java虛擬機器的約束條件。
- 準備:為被載入類的靜態欄位分配記憶體。Java 程式碼中對靜態欄位的具體初始化,則在初始化階段進行。
- 解析:編譯會對一個方法的呼叫,僧成一個包含方法所在類的名字,目標方法的引數等等資訊的符號引用,來指代要呼叫的方法,解析的目的是把符號引用解析稱為真正的引用。如果符號引用觸發的是一個未被載入的類的欄位或者類或者方法,那麼會觸發類的載入。但是未必會觸發類的連結與初始化。
規範中沒有要求瞭解的過程中完成解析,使用了符號引用,在執行位元組碼之前需要完成對符號引用的解析。
初始化
靜態欄位被final所修飾,型別是基本型別,或者字串,會被編譯器編譯為常量值,初始化由虛擬機器完成。
其他的賦值操作,靜態程式碼塊中的程式碼被編譯器置於同一個方法中client中。
初始化 操作是標記為常量值的欄位賦值,以及執行clinit的方法執行,虛擬機器通過加鎖的手段保證clinit方法僅被執行一次。