類加載過程
是Java虛擬機(JVM)將字節碼文件(.class文件)加載到內存中,并轉換為運行時數據結構的過程。這個過程可以分為多個步驟,每個步驟都有其特定的任務和目的。根據你提供的信息,以下是類加載過程的三個主要步驟:
1. 加載
在這個階段,類加載器通過一個類的全限定名來獲取定義此類的二進制字節流。這一步驟包括以下幾個子步驟:
- 定位字節源:類加載器需要找到包含類定義的字節碼文件。這些字節碼文件可能存在于本地文件系統、網絡資源、數據庫或者其他任何形式的存儲介質中。
- 讀取字節流:一旦找到了字節碼文件,類加載器會讀取該文件的內容,將其轉化為字節流。
- 創建類對象:類加載器使用讀取到的字節流來創建一個
java.lang.Class
對象,這個對象代表了正在被加載的類。
2. 鏈接
鏈接階段的主要任務是將字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構。這個階段又可以細分為以下三個子階段:
- 驗證:確保字節流中的信息符合Java虛擬機規范的要求,不會對虛擬機造成危害。驗證包括字節碼驗證、符號引用驗證等多個方面。
- 準備:為類的靜態變量分配內存,并設置默認初始值。例如,對于int類型的靜態變量,默認值為0;對于引用類型,默認值為null。
- 解析:將類的常量池內的符號引用替換為直接引用。符號引用是以字符串形式存在的,而直接引用可以直接指向目標。
3. 初始化
在初始化階段,JVM會執行類構造器<clinit>()
方法,這個方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊(static{}塊,中的語句合并產生的。初始化階段是執行類中定義的Java程序代碼(或者說是字節碼)的階段,前面的類加載過程中,除了在加載階段用戶應用程序可以通過自定義類加載器參與之外,其余動作完全由JVM主導和控制。到了初始化階段,才真正開始執行類中編寫的Java程序代碼(或者說是字節碼)。
類加載類型
1. 類加載器類型
- Bootstrap Class Loader
由JVM內部實現(如C++),負責加載核心類庫(如rt.jar
)。它是所有類加載器的根基,但沒有對應的Java對象,因此在代碼中不可直接訪問。 - Extension Class Loader
加載JRE擴展目錄(如jre/lib/ext
)中的類,父加載器為Bootstrap(但通常以null
表示)。 - System/Application Class Loader
加載應用程序類路徑(-classpath
或-cp
)的類,父加載器是Extension。 - User-Defined Class Loader
用戶自定義的類加載器(需繼承ClassLoader
類),可靈活指定其父加載器(默認父加載器是System)。
2. 包含關系
- 不是繼承關系:類加載器之間的層次通過組合實現(每個加載器持有父加載器的引用),而非類的繼承。例如,
ClassLoader
類中有一個parent
字段指向父加載器。 - 委派模型:加載類時,子加載器會先委派父加載器嘗試加載,父加載器失敗后子加載器才自行加載。這種“雙親委派”機制確保了核心類的安全性。
3. **圖示關系
Bootstrap Class Loader↑(隱含引用)
Extension Class Loader↑(parent字段引用)
System Class Loader↑(parent字段引用)
User-Defined Class Loader(可多個,各自獨立)
Java類加載器之間的關系通過委派模型協作,形成邏輯上的層次結構,但并非通過類繼承實現,而是通過對象間的引用組合(即包含關系)。具體如下:
// System Class Loader 的 parent 是 Extension Class Loader
ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
ClassLoader parent = systemLoader.getParent(); // 父加載器是 Extension
4. Optional的說明
- Optional可能指Java 9+模塊化系統中的類加載器(如
PlatformClassLoader
),或特定場景下的可選加載器(如OSGi、Tomcat的WebApp類加載器)。它們與上述加載器協作,但遵循相同的委派邏輯。
總結
類加載器通過委派鏈形成包含關系,每個加載器通過parent
字段引用父加載器,而非繼承。這種設計保障了核心類庫的隔離性與安全性,同時允許用戶自定義類加載邏輯。