繼上一篇JVM學習之路3-GC機制和GC收集器分析介紹完垃圾回收相關內容後,這篇說說類的加載機制。咱們平時在寫代碼的時候更多的是和對象打交道,不多去關心類的相關信息是怎麼來的,在以前的系列文章中咱們介紹過類信息是存放在哪的、對象是如何找到本身的類等內容,都沒有詳細介紹過類是如何來的,它是怎麼被加載到虛擬機裏的。
知識點
一、類文件結構
二、虛擬機加載類機制java
這裏整理了一幅圖先作總體展現
上面圖已經對各個結構作了簡單的說明,字段表集合是不包含方法的局部變量,這裏再介紹一下常量池。segmentfault
就是指字面量和符號引用,字面量即java語言層的常量概念,符號引用如:類和接口全限定名、字段方法名稱和描述符等。每種常量項都有本身的一個表結構,具體能夠再看一下書裏的表,這裏再也不作引用。通常java用Constant_utf8_info項來存類名和方法名,因此咱們平時定義類和方法的時候不能過長(65535),固然通常也不會那麼長。數組
一個類從加載進虛擬機內存到從內存中卸載,整個生命週期以下:
加載、驗證、準備、初始化、卸載這五個階段的順序是肯定的,如下6種狀況下必須先對類進行初始化:
一、遇到new、getstatic、putstatic、invokestatic指令,基本上就是new對象、靜態方法調用和靜態字段訪問。
二、反射調用。
三、父類沒初始化過先作初始化。
四、虛擬機啓動時執行主類要先初始化。
五、動態語言最終對應的方法靜態調用須要先初始化。
六、有默認方法的接口要在類實例化前進行初始化。安全
此階段把類從文件的二進制流轉換到方法區的運行時數據結構並生成class對象。除了從.class文件中加載類信息,咱們還能夠經過網絡、zip等壓縮包、或者在代碼中動態生成類信息。這裏須要注意的是:數組類不是由類加載器加載,數組類若是放的是引用類型,該引用類型是由類加載器來加載,該數組類會被標識在該類加載器的類名稱空間上,若是數組類放的不是引用類型,則會被標識在引導類加載器上。網絡
這是鏈接的第一個階段,主要是爲了保證加載的類字節流符合虛擬機規範,防止惡意代碼的侵入,保護虛擬機的安全,爲何說java是類型安全的,這部分就是主要緣由,主要有以下幾部分校驗:
一、文件格式校驗,好比文件的魔數是否符合定義。
二、元數據校驗,對字節碼描述的信息進行校驗(看字節碼:javap -verbose xxxClass),好比是否繼承了不被容許繼承的類。
三、字節碼驗證,經過數據流和控制流分析來確保語義是合法的、符合邏輯的。
四、符合引用驗證,發生在虛擬機將符號引用轉換爲直接引用時,好比檢查是否缺乏依賴的外部方法、類等資源。數據結構
正式爲類中的變量分配內存和設置初始值。舉個例子:佈局
public static int value = 123;
如上代碼,在準備階段的時候會將value設置爲0,而不是123,真正賦值123是在初始化階段。固然若是是常量(用final修飾),則會直接初始化爲123。學習
將常量池中符號引用替換爲直接引用的過程,包括類/接口解析、方法解析、字段解析、接口方法解析等。
符號引用:就是一個字面量,好比類的全限定名,只要能惟一識別該類就行,和內存佈局無關。
直接引用:和內存佈局相關,內存中要已經存在該目標,直接引用至關於直接定位到該目標。spa
類加載過程的最後一個步驟,虛擬機將主導權交給應用程序。準備階段在分配內存和設置初始值以後,初始化階段就會真正設置咱們賦予的初始值,就是在執行類構造器<clinit>()方法的過程。靜態語句塊中只能訪問 到定義在靜態語句塊以前的變量,定義在它以後的變量,在前面的靜態語句塊能夠賦值,可是不能訪問。code
在上面的加載機制中提到了類加載器,它除了能夠加載類之外,還能夠確認一個類在虛擬機中的惟一性(對於任意一個類,都必須由加載它的類加載器和這個類自己一塊兒共同確立其在Java虛擬機中的惟一性),同一個類被同一個虛擬機加載,只要加載器不一樣,那類一定也不一樣。
java虛擬機經典的雙親委派模式。一幅圖:
啓動類加載器(BootstrapClassLoader):負責加載存放在 <JAVA_HOME>\lib目錄,或者被-Xbootclasspath參數所指定的路徑中存放的類到虛擬機中。
擴展類加載器(ExtClassLoader):負責加載<JAVA_HOME>\lib\ext目錄中,或者被java.ext.dirs系統變量所 指定的路徑中全部的類庫。
應用程序類加載器(AppClassLoader):負責加載用戶類路徑 (ClassPath)上全部的類庫。
基本機制:每當加載一個類的時候,虛擬機會先用啓動類加載器進行加載,加載不到再用擴展類加載器,再加載不到就用應用程序類加載器進行加載。這樣能夠保證一個類在虛擬機裏惟一。
本篇主要介紹了類文件結構以及類加載機制,整個類的加載過程仍是比較清晰且簡單的,你們也能夠本身試着定一個類加載器來加載類,跟進代碼看一下雙親委派模式具體怎麼走。