JVM類加載分爲5個過程:加載,驗證,準備,解析,初始化,使用,卸載,如圖: java
沒錯,以上就是抽象的類加載過程,寫類加載過程的都是大同小異,圖我也是copy來的,而後聯想到近期剛剛入職新公司,下面我入職新公司來解釋類加載(絕對通俗易懂):程序員
場景:企業A發offer,約定6月17號入職,爲我分配了部門,入檔,部門領導人在周例會彙報中報備部門成員XXX(待入職)面試
(1) 找:經過一個類的全限定名來獲取此類的class字節碼二進制流。(給一個名稱找到class字節碼文件=經過面試郵箱發offer)安全
(2) 轉:將這個字節碼二進制流中的靜態存儲結構轉化爲方法區中的運行時數據結構。(轉化爲線程共享內存方法區的運行時數據結構=???這個很差解釋)數據結構
(3) 存:在內存中生成一個表明該類的java.lang.Class對象,做爲方法區中這個類的各類數據的訪問入口。(在方法區中爲類實例化一個源對象,目的是做爲方法區這個類的各類數據的訪問入口=企業A爲我分配部門,入檔,領導內部溝通時能夠用XXX部門的XXX人員)函數
注: 1.在JVM中類的惟一性是由類的全名和類加載器肯定的,相同的class文件被不一樣的類加載器加載生成的兩個類是不一樣的。 2.加載階段和鏈接階段的部份內容是交叉進行的,加載階段還沒有結束,鏈接階段可能就已經開始了。 3.源對象只會存放靜態資源,如static變量線程
場景:6.17號,本人入職遞交材料,如體檢/上家企業的離職報告,hr領我到對應工位,並提供企業文化和流程等相關文檔文件,並在座位上配備人員信息(其實就是一張卡片,職位姓名之類的信息),目的讓其餘人能夠看見cdn
驗證:確保加載的類信息符合JVM規範,沒有安全方面的問題 (對實例化對象進行各類校驗,好比語法/符號 = hr檢查材料是否交齊,並有沒有做假)對象
準備:正式爲類變量(static變量)分配內存並設置類變量初始值的階段,這些內存都將在方法區中進行分配 (在源對象的基礎上爲static變量開闢空間並設置初始值=hr領我到工位,做爲個人辦公區)blog
解析:虛擬機常量池的符號引用替換爲字節引用過程 (將抽象的指令轉換爲具體的地址指令=配備信息卡片,當其餘找我時,只須要看到卡片上的名字就能夠了)
注: 1.public static Integer value=1;在準備階段的值實際上是爲0的。須要注意的是常量是在準備階段賦值的:public static final Integer value =1 ;在準備階段value就被賦值爲了1;
2.解析的過程:好比在類A中調用了B的方法;你們想想,咱們編譯完成.class文件後其實這種對應關係仍是存在的,只是以字節碼指令的形式存在,好比 "invokespecial #2"你們能夠猜到#2其實就是咱們的類B了,那麼在執行這一行代碼的時候,JVM咋知道#2對應的指令在哪,這就是一個靜態的傢伙,假如類B已經加載到方法區了,地址爲(#f00123),因此這個時候就要把這個#2轉成這個地址(#f00123),這樣JVM在執行到這裏時就知道B類在哪了,就能夠去調用了。甚至Java 虛擬機爲每一個類都準備了一張方法表來存放類中全部的方法。當須要調用一個類的方法的時候,只要知道這個方法在方法表中的偏移量就能夠直接調用該方法了
場景:入職以後,在以前入檔的基礎上初始化我的信息和各類帳號,如郵箱,域帳號域密碼等
注:1.前面的類加載過程當中,除了加載(Loading)階段用戶應用程序能夠經過自定義類加載器參與以外,其他動做徹底由虛擬機主導和控制。
2.一個類什麼時候被初始化能夠分爲如下幾類:A:建立類的實例(new)。B:訪問某個類或接口的靜態變量,或者對該靜態變量賦值。C:調用類的靜態方法。D:經過反射方式執行以上三種行爲。E:初始化子類的時候,會觸發父類的初始化。F:Java虛擬機啓動時被標明爲啓動類的類。(有main方法的類)
3.初始化完成之後,類被存放在方法區,注意哦,此時並無存放在堆內存中。只有當對象實例化進入堆內存中之後纔會對非靜態變量進行初始化賦值。
場景:有帳號密碼了,能夠工做了,直到下次離職,開始工做啦。。。。。。。
1.使用:直接new或者經過反射.newInstance,堆內存建立實例化對象.(等同於開始工做了,領導安排任務)
2.卸載:卸載是自動進行的,也就是GC,gc在方法區也會進行回收.不過條件很苛刻,感興趣能夠本身看一看,通常都不會卸載類.(下次離職。。。。😂)