溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java類加載過程分為哪些步驟

發(fā)布時間:2022-01-14 11:00:52 來源:億速云 閱讀:163 作者:iii 欄目:大數(shù)據

本篇內容介紹了“java類加載過程分為哪些步驟”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

一般來說,我們把Java的類加載過程分為三個主要步驟:加載、鏈接、初始化
加載階段(Loading)

它是Java將字節(jié)碼數(shù)據從不同的數(shù)據源讀取到JVM中,并映射為JVM認可的數(shù)據結構(Class對象)。這里的數(shù)據源可能是各種各樣的形態(tài),如jar文件、class文件,甚至是網絡數(shù)據源等。如果輸入數(shù)據不是ClassFile的結構,則會拋出ClassFormatError。
加載階段是用戶參與的階段,我們可以自定義類加載器,去實現(xiàn)自己的類加載過程。 

鏈接階段(Linking)

這是核心的步驟,簡單說是把原始的類定義信息平滑地轉化入JVM運行的過程中。這里可進一步細分為三個步驟:

  • 驗證(Verification),這是虛擬機安全的重要保障,JVM需要核檢字節(jié)信息是符合Java虛擬機規(guī)范的,否則就被認為是VerifyError。這樣就防止了惡意信息或者不合規(guī)的信息危害JVM的運行。驗證階段有可能觸發(fā)更多class的加載。

  • 準備(Preparation),創(chuàng)建類或接口中的靜態(tài)變量,并初始化靜態(tài)變量的初始值。但這里的“初始化”和下面的顯式初始化階段是有區(qū)別的,側重點在于分配所需要的內存空間,不會去執(zhí)行更進一步的JVM指令。

  • 解析(Resolution),在這一步會將常量池中的符號引用(symbolic reference)替換為直接引用。在Java虛擬機規(guī)范中,詳細介紹了類、接口、方法和字段等各個方面的解析。 

初始化(Initialization)

這一步真正去執(zhí)行類初始化的代碼邏輯,包括靜態(tài)字段復制的動作,以及執(zhí)行類定義中的靜態(tài)初始化塊內的邏輯。編譯器在編譯階段就會把這部分邏輯整理好,父類型的初始化邏輯優(yōu)先于當前類型的邏輯。 

Java 8之前的類加載器

啟動類加載器(Bootstrap Class-Loader),加載jre/lib下面的jar文件,如rt.jar。它是個超級公民,即使是在開啟了Security Manager的時候,JDK仍賦予了它加載的程序AllPermission。

對于做底層開發(fā)的工程師,有的時候可能不得不去試圖修改JDK的基礎代碼,也就是通常意義上的核心類庫,我們可以使用下面的命令行參數(shù)。

# 指定新的 bootclasspath,替換 java.* 包的內部實現(xiàn)
java -Xbootclasspath:<your_boot_classpath> your_App

# a 意味著 append,將指定目錄添加到 bootclasspath 后面
java -Xbootclasspath/a:<your_dir> your_App

# p 意味著 prepend,將指定目錄添加到 bootclasspath 前面
java -Xbootclasspath/p:<your_dir> your_App
 

用法其實很易懂,例如,使用最常見的“/p”,既然是前置,就有機會替換個別基礎類的實現(xiàn)。

我們一般可以使用下面方法獲取父加載器,但是在通常的JDK/JRE實現(xiàn)中,擴展類加載器getParent()都只能返回null。

public final ClassLoader getParent()
 

擴展類加載器(Extension or Ext Class-Loader),負責加載我們放到jre/lib/ext目錄下面的jar包,這就是所謂的extension機制。該目錄也可以通過設置“java.ext.dirs”來覆蓋

java -Djava.ext.dirs=your_ext_dir HelloWorld
 

應用類加載器(Application or App Class-Loader),就是加載我們最熟悉的classpath的內容。這里有一個容易混淆的概念,系統(tǒng)(System)類加載器,通常來說,其默認就是JDK內建的應用類加載器,但是它同樣是可能修改的,比如:

java -Djava.system.class.loader=com.yourcorp.YourClassLoader HelloWorld

如果我們指定了這個參數(shù),JDK內建的應用類加載器就會成為定制加載器的父親,這種方式通常用在類似需要改變雙親委派模式的場景。

具體參考下圖:

java類加載過程分為哪些步驟

 
雙親委派模型

談到類加載一個躲不開的話題就是“雙親委派模型”,簡單說就是當類加載器(Class-Loader)試圖加載某個類型的時候,除非父加載器找不到相應的類型,否則盡量將這個任務代理給當前加載器的父加載器去做。

參考上面這個結構圖就很容易理解了。試想,如果不同類加載器都自己加載需要的某個類型,那么就會出現(xiàn)多次重復加載,完全是種浪費。

通常類加載器機制有三個基本特征:

  • 雙親委派模型。但不是所有類加載都遵守這個模型,有的時候,啟動類加載器所加載的類型,是可能要加載用戶代碼的。比如JDK內部的ServiceProvider/ServiceLoader機制,用戶可以在標準API框架上,提供自己的實現(xiàn),JDK也需要提供些默認的參考實現(xiàn)。例如,Java中JNDI、JDBC、文件系統(tǒng)、Cipher等很多方面,都是利用的這種機制,這種情況就不會用雙親委派模型去加載,而是利用所謂的上下文加載器。

  • 可見性。子加載器可以訪問父加載器加載的類型,但是反過來是不允許的。不然,因為缺少必要的隔離,我們就沒有辦法利用類加載器去實現(xiàn)容器的邏輯。

  • 單一性。由于父加載器的類型對于子加載器是可見的,所以父加載器中加載過的類型,就不會在子加載器中重復加載。但是注意,類加載器“鄰居”間,同一類型仍然可以被加載多次,因為互相不可見。

“java類加載過程分為哪些步驟”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI