1. 程式人生 > >java類加載機制概念

java類加載機制概念

native lan 技術 自定義 rt.jar 紅色 委派 java類加載 常量池

首先類加載在整個體系結構的哪一個環節呢?見紅色圈住的部分。

技術分享圖片

類加載器分為那幾個過程呢?五個過程

技術分享圖片

  • 加載
    • 根據類的全限定名(簡單理解為類的絕對路徑,見附錄),找到指定的字節碼文件,並在內存中生產一個java.lang.Class的對象,存放在方法區中。
  • 驗證
    • 作用:確保字節碼文件中包含的信息符合Class文件格式規範,對虛擬機來說是安全的。
    • 規則一直在更新,大體有四種
      • 文件格式驗證
        • 基於二進制字節流進行分析。
      • 元數據驗證(可以理解成是對類層面的信息驗證)
        • 對類的元數據進行語義分析。
      • 字節碼驗證(對方法層面的信息驗證)
        • 對方法體語義分析。
      • 符號引用驗證
        • 驗證根據引用能否找到對應的類、方法、字段。
    • 如果確認字節碼文件是安全的,通過 -Xverify:none 關閉大部分驗證。
  • 準備
    • 在方法區中為類的靜態變量分配內存並初始化。
  • 解析
    • 將常量池中的符號引用替換為直接引用的過程。
  • 初始化
    • 執行類構造器<client>方法,<client>方法是由編譯器自動收集的類中的類變量賦值操作和靜態語句塊中的語句。並且會保證父類的<client>方法先執行。

加載過程由誰來執行的

類加載器 classLoader,也就是 Java.lang.ClassLoader。核心函數是loadClass

protected synchronized
Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 首先檢查類是不是已經被加載 Class c = findLoadedClass(name); if (c == null) { try { if (parent != null) { //如果父類不為空,優先檢查父類的 c = parent.loadClass(name, false
); } else { //否則檢查當前的 c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { // 如果還是找不到,就觸發子類本身的findClass方法去找 c = findClass(name); } } if (resolve) { resolveClass(c); } return c; }

那類加載器有哪幾種

兩大類,四小種:JDK默認提供的三種,用戶自定義的一種。

技術分享圖片

默認的三種有(非繼承關系)

  • Bootstrap ClassLoader 啟動類加載器,沒有父類。
    • 一般是native code(C++)實現
    • 用於加載虛擬機的核心類(<JAVA_HOME>/jre/lib/rt.jar),包括擴展類/系統類加載器
  • Extension ClassLoader 擴展類加載器,父類加載器為空
    • java實現,是rt.jar中sun.misc.Launcher的內部類sun.misc.Launcher$ExtClassLoader (miscellaneous)
    • 用於加載擴展庫中的類(<JAVA_HOME>/jre/lib/ext)
  • System ClassLoder 父類加載器Ext ClassLoader
    • java實現,是rt.jar中sun.misc.Launcher的內部類sun.misc.Launcher$AppClassLoader
    • 用於CLASS_PATH中的類

用戶自定義的有一種 父類是 System ClassLoader

  • 繼承自java.lang.ClassLoader

這麽多加載器,如果我兩個加載器中有同名文件怎麽辦?

這裏有一個雙親委派的概念。就是當查找一個類的時候,會一層一層的向上委托查詢,如果父類加載器有對應的類,就直接從父類加載該類。

這樣的雙親委派有好處,但是有些場景我們是希望破壞雙親委派的

  • 場景一:我們想在頂層的classLoader中加載底層的classLoader
    • 可以在線程中放入底層的classLoader到Thread.setContextClassLoader()中,然後在頂層的classLoader中使用Thread.getContextClassLoader()加載第三方的classLoader實現。
  • 場景二:實現類熱部署
    • 一個class只能被一個classLoader加載一次,當需要實現代碼熱部署的時候可以每次都new一個自定義的classLoader來加載新的Class文件。
  • 場景三:Tomcat中使用WebAppClassLoader進行單獨加載,加載不了再去委托父加載器去加載。

附錄

  • 類的全限定名:可以理解成類的絕對路徑,一般規則是包名.外部類名$內部類名。
    • 成員內部類:包名.外部類名$內部類名
    • 匿名內部類:包名.外部類名$由1開始的正整數-按照類裝載順序依次排列
    • 局部內部類:包名.外部類名$由1開始的正整數後跟局部類名-其中數字部分是局部類在外部類上下文出現的先後順序

java類加載機制概念