您好,登錄后才能下訂單哦!
本篇內容主要講解“Java類加載機制和雙親委派是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java類加載機制和雙親委派是什么”吧!
類加載器歷史
在 Java 1.1 及之前的版本中,各個類加載之間不存在聯系。 例如系統類加載器負責加載應用,以及 classpath 目錄下的 class 文件和資源; 而 applet 的類加載器負責和服務器端交互以加載 applets 應用和它相關的 class 文件和資源。
在 J2SE 1.2 版本(如果你知道 J2SE 這個稱呼,證明你是一名老程序員了,哈哈),類加載器之間產生了一種關系,這種關系也就是我們熟知的 parent delegation(中文譯作雙親委派) 機制。
雙親委派是什么
簡單來說雙親外派機制就是當前的類加載器去加載一個 class 數據之時,它會先委托它的父加載器去做這件事,父加載器它會遞歸去委托自己的父加載器去加載,直到父加載器不存在,或者父加載器加載不到的時候才自己去加載(注意:此處的父加載器并不是 Java 中的繼承關系,而是職責上的關系)。
JDK 中提供了如下 3 種常見的類加載器:
BootstrapClassLoader: 俗稱啟動類加載器,是最頂層的類加載器,也稱為 root 類加載器,負載加載 JRE/lib/rt.jar 中的 class 文件,加載目錄可以通過 -Xbootclasspath 改變。
ExtClassLoader: 俗稱擴展類加載器,負責加載 JRE/lib/ext 目錄下的 class 文件,可以通過設置環境變量 java.ext.dirs 改變加載目錄,優先級次于 BootstrapClassLoader。
AppClassLoader: 俗稱應用類加載器,也稱系統類加載器,負責加載我們的應用 class 文件和 classpath 環境變量指定目錄下的 class 文件,優先級次于 ExtClassLoader。
這種機制的好處是可以明確的分工每種類加器的職責,同時保證 class 加載的唯一性,當一個 class 文件被其父加載器加載過以后,后續類加載器就不會加載了。
雙親委派機制的弊端
它也有不足之處,例如 Java 的 SPI 機制,這種雙親委派機制就不能很好的支持,因此又引入了上下文類加載器。
SPI 全稱 Service Provider Interface,它是 Java 發現服務的一種規范。JDK 負責提供服務的接口規范,第三方廠商負責來實現該服務。例如我們熟知的 JDBC 就是采用這種機制來實現。
JDBC 的接口規范由 JDK 定義在 rt.jar 中,我們知道這個 jar 中 class 是由 BootstrapClassLoader 來負責加載的,然而 JDBC 的實現類是由 AppClassLoader 來負責加載的。 因此當 JDBC 接口需要用到實現類時就無法完成操作了,但是雞賊的 Java 大神們引入了線程上下文類加載器來解決這個問題。
如果你不做特殊設置的話,通常線程的上下文類加載器就是系統類加載器,即為 AppClassLoader,使用它恰巧可以加載廠商提供的實現類的 class 文件,有興趣的同學可以參考 JDK 中 java.sql 包下的 DriverManager 中的部分源碼如下:
// Worker method called by the public getConnection() methods.
private static Connection getConnection
(
throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null ;
synchronized (DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null ) {
callerCL = Thread.currentThread().getContextClassLoader();
}
/**省略部分源碼**/
}
通過上面我們了解了 JDK 中幾種類加載器的分工,也討論了雙親委派加載機制的本質。 接下來讓我們一起看看一個 class 文件在被加載到 Java 運行時環境中變成一個可以使用的 java.lang.Class 實例之前經過了哪些步驟。
類加載步驟
一個 class 文件變為 Java 運行時環境中的可以使用的 Class 實例時,主要經過了加載、鏈接和初始化 3 個步驟。
1. 加載
這個階段總共會做 3 件事:
1.通過類的全限定名獲得定義該類的二進制字節流。
2.將字節流轉換為 JVM 運行時數據結構。
3.在 JVM 中生成代表該類的 Class 實例,以供后續使用。
2. 鏈接
該階段主要分為了驗證、準備和解析 3 個步驟:
驗證 是鏈接第一步,首先驗證文件格式,確認 class 文件否和當前虛擬機規范,例如以魔數 0xCAFEBABE 開頭,class 版本號在當前虛擬機處理范圍內等等; 其次是分析代碼語義,確認其描述的語義否和 Java 語言規范;
準備 是鏈接的第二步,該階段將為類變量(static 修飾)分配內存,如果它是一個常量(static final 修飾),則直接初始化為目標常量。
解析 是鏈接的第三步,該階段虛擬機會將常量池中符號引用替換為直接引用。
3. 初始化
該階段是最貼近程序員編碼的,主要執行所有類變量的初始化和靜態代碼塊,同時虛擬機會保證在子類初始化操作之前完成父類(接口除外,接口只有在直接使用到接口的靜態屬性時候才會初始化)的初始化。
到此,相信大家對“Java類加載機制和雙親委派是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。