目錄
- 類加載器
- 雙親委派模型
- 為什么要用這種類加載機制
類加載器
我們撰寫的.java檔案被編譯器編譯成.class的位元組碼檔案,類加載器ClassLoader負責將這些位元組碼檔案加載到記憶體中去執行,
JVM提供了三種類加載器:
引導類加載器Bootstrap:最頂層類加載器,負責加載JDK核心類別庫,C++語言實作
擴展類加載器ExtClassLoader:負責加載JDK擴展類別庫,Java語言實作
應用類加載器AppClassLoader:負責加載我們自己定義的類和第三方jar包中的類,Java語言實作
AppClassLoader的父加載器是ExtClassLoader,ExtClassLoader的父加載器是Bootstrap,
雙親委派模型
雙親委派機制:當一個類加載器收到類加載的請求時,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父加載器完成,每個類加載器都是如此,因此所有的加載請求最終都會傳送到頂層的引導類加載器中,只有當父加載器在自己的搜索范圍內找不到指定的類時,子加載器才會嘗試自己去加載,如下圖所示:

加載程序:
當應用類加載器接到加載某個類的任務時,例如:java.lang.String
(1)會先在記憶體中搜索這個類是否加載過,如果是,就回傳這個類的Class物件,不去加載,
(2)如果沒有找到,即沒有加載過,會把這個任務提交給父加載器,
當擴展類加載器接到類加載的請求時
(1)會先在記憶體中搜索這個類是否加載過,如果是,就回傳這個類的Class物件,不去加載,
(2)如果沒有找到,即沒有加載過,會把這個任務提交給父加載器,
當引導類加載器接到類加載的請求時
(1)會先在記憶體中搜索這個類是否加載過,如果是,就回傳這個類的Class物件,不去加載,
(2)如果沒有找到,即沒有加載過,去它負責的范圍內嘗試加載,
① 如果能夠加載,那么就自己加載并回傳這個類的Class物件,結束,
② 如果不能加載,那么會把這個任務往回傳,讓子加載器去加載,
擴展類加載器接到父加載器回傳的任務后,去它負責的范圍內嘗試加載,
① 如果能夠加載,那么就自己加載并回傳這個類的Class物件,結束,
② 如果不能加載,那么會把這個任務往回傳,讓子加載器去加載,
應用類加載器接到父加載器回傳的任務后,去它負責的范圍內嘗試加載,
① 如果能夠加載,那么就自己加載并回傳這個類的Class物件,結束,
② 如果不能加載,那么就拋出ClassNotFoundException
為什么要用這種類加載機制
你可能會想到兩個問題:
(1)為什么不用就近原則,子加載器能夠加載就讓子加載器加載好了,卻要委托給父加載器加載?
(2)檢查一個類是否加載過為什么要重復搜索,既然加載請求最終要傳給頂層的引導類加載器,那么為什么不一開始就交給頂層的引導類加載器,自頂向下嘗試加載?
對于問題(1):保證程式的安全性,防止系統級別的類被替換,例如類java.lang.Object,最終要委派給處于模型最頂層的引導類加載器進行加載,它會優先jdk中提供的Object類,而不是我們自己定義的,
驗證:我們自己定義一個Object類,包名也為java.lang:
package java.lang;
public class Object {
public static void main(String[] args) {
System.out.println("自定義的Object類");
}
}
發現運行報錯:

明明在String類中定義了main方法,為什么提示找不到呢?因為實際加載的是核心類別庫中Object類,里面是沒有main方法的,
對于問題(2):防止同一個類被重復加載,每層類加載器都有自己的確認邏輯,同一個類被不同的類加載器加載,會被識別為不同的類,只有每層的類加載器都確認自己沒有加載過,才能最終判定這個類沒有被加載,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/43125.html
標籤:Java
