虛擬機(jī)類加載機(jī)制

一、類的生命周期

加載 -> 驗證 -> 準(zhǔn)備 -> 解析 -> 初始化 -> 使用 -> 卸載

有且僅有以下情況,JVM必須立即對類進(jìn)行初始化:

  1. new、getstatic、putstatic、invokestatic
  2. 使用反射對類進(jìn)行調(diào)用時
  3. 初始化一個類,發(fā)現(xiàn)其父類還未進(jìn)行初始化,則先初始化父類
    (接口初始化,并不要求其父接口初始化,只有在真正使用到父接口(如引用接口中定義的常量)才會初始化;
    調(diào)用類中的常量,不會觸發(fā)初始化)
  4. JVM啟動時,會先初始化main方法所在類

注意以下幾點,不會觸發(fā)類的初始化

  1. 通過數(shù)組引用類,不會觸發(fā)初始化,如:
    SomeClass[] someClassArr = new SomeClass[10];
  2. 常量在編譯階段會存入調(diào)用類的常量池,本質(zhì)上并沒有直接引用到定義類,如:
    System.out.println(Constants.HELLO);
二、類的加載過程
  1. 加載
    • 通過類的全限定名,獲取類的二進(jìn)制字節(jié)流
    • 將字節(jié)流代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)
    • 方法區(qū)(針對HotSpot而言)生成一個代表此類的java.lang.Class對象。
      這個對象將作為程序訪問方法區(qū)中這些類型數(shù)據(jù)的外部接口
  2. 驗證
    其中,符號引用驗證,發(fā)生在JVM將符號引用轉(zhuǎn)化為直接引用的時候(解析階段)。
  3. 準(zhǔn)備
    類變量(被static修飾的變量)分配內(nèi)存并設(shè)置初始值,這些變量所使用的內(nèi)存,在方法區(qū)分配
    特殊情況:如果是常量,則在準(zhǔn)備階段直接賦給定值
  4. 解析
    JVM將常量池內(nèi)的符號引用替換為直接引用的過程,包括以下常量:
  • CONSTANT_Class_info
  • CONSTANT_Methodref_info
  • CONSTANT_Fieldref_info
  • CONSTANT_InterfaceMethodref_info
  1. 初始化
    執(zhí)行<cinit>的過程,c指class的意思。
    JVM會保證<cinit>只執(zhí)行一次,即便在多線程環(huán)境中
    <cinit> 是編譯器自動收集類中所有static變量的賦值動作和static{}, 并按源文件中出現(xiàn)順序形成的
三、類加載器

每一個類加載器,都擁有一個獨立的類命名空間,【命名空間 + 類全限定名】唯一確定一個類。

雙親委派模型
父加載器反饋無法加載時,才由子加載器自己加載

  1. 避免重復(fù)加載
  2. 防止JVM類(如Object.class被覆蓋)
  • Bootstrap ClassLoader
    <JAVA_HOME>/lib下,并且僅按照文件名識別(如rt.jar)
  • 擴(kuò)展類加載器
    <JAVA_HOME>/lib/ext下
  • 應(yīng)用程序類加載器
    classpath指定路徑
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容