Java的類加載機制

一、什么是Java的類加載機制

先來看Java程序運行圖:


Java的類加載機制所做的工作就是將經(jīng)編譯器編譯后的.class文件中的二進制數(shù)據(jù)讀入到內存中,將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內,然后在堆區(qū)創(chuàng)建一個 java.lang.Class對象,用來封裝類在方法區(qū)內的數(shù)據(jù)結構。
.class文件可能來源于本地磁盤、數(shù)據(jù)庫、網(wǎng)絡傳輸或者jar包等。

二、Java類加載的流程

Java的類加載主要分為以下5個階段:

1. 加載

在本階段,JVM主要做以下3個事情:
(1) 通過一個類的全限定名來獲取其定義的二進制字節(jié)流;
(2) 將這個字節(jié)流所代表的靜態(tài)存儲結構轉為方法區(qū)的運行時數(shù)據(jù)結構;
(3) 在Java 堆中生成一個代表這個類的java.lang.Class 對象,作為方法區(qū)中這些數(shù)據(jù)的訪問入口。

2.驗證

即驗證所加載類的正確性,是JVM保證安全的一道重要屏障,主要驗證以下幾個方面:

  • 文件格式驗證:驗證所加載的二進制文件格式是否正確。
  • 元數(shù)據(jù)驗證:對類文件中所定義的語義進行驗證,如訪問修飾符使用是否正確等等。
  • 字節(jié)碼驗證:主要通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的、符合邏輯的。
  • 符號引用驗證:負責對各種符號引用進行匹配性校驗,保證外部依賴真實存在,并且符合外部依賴類、字段、方法的訪問性。

3. 準備

該階段為類變量(static)分配內存并設置初始值,但是對實例變量不會。如:
對于private static String a = "s",會分配內存并設置初始值,注意這里的初始值是變量類型的默認值null,并不是s。
對于常量(同時用final和static修飾)private static final String b = "s"會分配值s。
對于private String b = new String("b")則不會處理。

4. 解析

該階段JVM將符號引用轉化為直接引用
符號引用:即用一組符號代表引用的目標。如在學校中同學給你取的外號。
直接引用:目標的指針、相對偏移量或者句柄。即在學校中唯一指向你本人的學號。

5.初始化

類加載過程的最后一步,在該階段中JVM為類中的變量賦值, 如在準備階段中只賦了默認值的變量,在這里會賦上真實值,同時也會為實例變量賦值。即該階段會類的構造器。

三、Java中的類加載器

Java中自帶三個加載器:
1. Bootstrap ClassLoader
最頂層的加載器,加載核心類庫,即jre/lib底下的文件,如rt.jar。
2. Extension or Ext Class-Loader
擴展類庫加載器,加載jre/lib/ext目錄下的jar包和class文件。還可以加載-D java.ext.dirs選項指定的目錄。
3. Appclass Loader
應用類加載器,加載當前應用classpath下的所有類。

除了以上類加載器之外,還可以自定義加載器。Java的類加載器是一個分級結構:


類加載器層次圖

四、雙親委派模型

Java的類加載采用了雙親委派模型,如上面的類加載器層次圖所示,當一個類加載器收到加載任務時,會先交予它的父加載器去執(zhí)行,如此一層一層往上知道最頂級的類加載器。只有當父類加載器無法完成任務時,才會交由自己來加載,這就是雙親委派模型。
雙親委派模型的好處:

  1. 避免重復加載,父類已經(jīng)加載過的類,子類無需重新加載。
  2. 更加安全,可以保證同一個類被特定的加載器加載,防止用戶隨意定義加載器來加載核心的api。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容