JVM把描述類的數據從Class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終造成能夠被虛擬機直接使用的Java類型。這就是類加載機制。java
Class文件結構中只有兩種數據類型:數組
- 無符號數:屬於基本的數據類型,以u一、u二、u四、u8分別表明一、二、四、8個字節的無符號數,能夠用來描述數字、索引引用、數量值、或者按照UTF-8編碼的字符串值;
- 表:由多個無符號數或者其餘表做爲數據項構成的複合數據類型,全部表都習慣以"_info"結尾;
- 因此,Class文件本質上就是一張表;
Class文件結構的內容組成:安全
- 魔數:每一個Class文件的前4個字節,JAVA語言魔數:CAFEBABE,16進制數,惟一左右就是確認文件是不是一個被虛擬機接受的Class文件;
- Class文件版本:Class文件第五、6個字節是次版本號,七、8個字節是主版本號;
- 常量池:從第9個字節開始,主要存放兩大類常量:(1)字面量;(2)符號引用;
- 訪問標誌:緊跟常量池以後的兩個字節表明訪問標誌,表明類或接口的層次信息;
- 類索引、父類索引與接口索引集合:緊跟訪問標誌以後的就是類索引、父類索引與接口索引,都是u2類型數據,Class文件中由這三項數據來肯定類的繼承關係;
- 字段表集合:緊接着就是字段表集合,用於描述接口或類中聲明的變量;
- 方法表集合:緊接着就是方法表集合,用於描述接口或類中聲明的方法;
- 建立類的實例:使用new關鍵字實例化對象;
- 訪問類的靜態變量:getstatic或putstatic,讀取或設置一個類的靜態變量(不包括被final修飾的靜態變量);
- 訪問類的靜態方法:invokestatic調用一個類的靜態方法;
- 使用java.lang.reflect進行反射調用:如,Class.forName("xxxxx");
- 子類初始化時,會先初始化父類;
- 經過子類引用父類的靜態字段,不會致使子類初始化,只會初始化父類;
- 經過數組定義來引用類,不會觸發類的初始化;
- 常量在編譯階段會存入調用類的常量池中,本質上並無直接引用到定義常量的類,由於不會觸發定義常量的類初始化;
- 經過類的全限定名稱獲取定義此類的二進制流;
- 將二進制流靜態結構轉化爲方法區的運行時數據結構;
- 在內存中生成一個表明這個類的java.lang.Class對象。對於HotSpot虛擬機,Class對象是存放在方法區裏的;
主要做用就是確保Class文件的字節流中包含的信息符合當前虛擬機的要求,而且不會危害虛擬機自身安全;數據結構
- 文件格式驗證:對檢查格式、版本;
- 元數據驗證:對字節碼進行語義分析;
- 字節碼驗證;
- 符號引用驗證;
- 正式爲類變量分配內存,內存在方法區中進行分配,類變量是指static修飾的變量;
- 設置類變量的初始值,這個初始值一般狀況下是數據類型的零值,如:public static int value = 123;初始值是0,不是123,賦值123動做會在初始化階段纔會執行;
將Class文件的常量池內的符號引用替換爲直接引用;函數
真正開始執行類中定義的Java程序代碼,初始化過程就是執行類構造器()方法的過程;編碼
- ()方法會自動收集類中全部類變量(static)的賦值動做和靜態代碼塊,編譯器收集順序由代碼出現順序決定;
- ()方法與類實例構造函數不一樣,虛擬機會保證父類的()執行完畢後再執行子類的()方法;
- 根類加載器(Bootstrap ClassLoader):其負責加載Java的核心類,好比String、System這些類;
- 拓展類加載器(Extension ClassLoader):其負責加載JRE的拓展類庫;
- 系統類加載器(System ClassLoader):其負責加載CLASSPATH環境變量所指定的JAR包和類路徑;
- 用戶類加載器:用戶自定義的加載器,以類加載器爲父類
雙親委派機制:若是一個類加載器在接到加載類的請求時,它首先不會本身嘗試去加載這個類,而是把這個請求任務委託給父類加載器去完成,依次遞歸,若是父類加載器能夠完成類加載任務,就成功返回;只有父類加載器沒法完成此加載任務時,才本身去加載。cdn
Java類隨着加載它的類加載器一塊兒具有了一種帶有優先級的層次關係。好比,Java中的Object類,它存放在rt.jar之中,不管哪個類加載器要加載這個類,最終都是委派給處於模型最頂端的啓動類加載器進行加載,所以Object在各類類加載環境中都是同一個類。若是不採用雙親委派模型,那麼由各個類加載器本身取加載的話,那麼系統中會存在多種不一樣的Object類。對象