經過上節的講解,我們已經知道了Java代碼——》字節碼的過程,產生了字節碼,下一步就是將字節碼讀入虛擬機,虛擬機將該部分分爲七個步驟:
加載->驗證->準備->解析->初始化->使用->卸載
我們主要研究前5步。
加載
- 讀入二進制字節流,並不限定是class文件,可以是zip,jar,網絡獲取或者其他。
- 將字節流代表的靜態結構轉換爲方法區的運行時數據結構
- 在堆中創建代表這個類的java.lang.class對象,作爲方法區這些數據的訪問入口
驗證
- 文件格式驗證,由於虛擬機只規定了讀入的是二進制字節流,並未規定必須是class文件,所以有可能是惡意的二進制流,爲了防止其破壞虛擬機,所以對其文件格式進行驗證:魔數是否0xCAFEBABE開頭,主次版本等。
- 元數據驗證,對類的元數據信息進行語義進行校驗,保證不存在不符合Java規範的元數據。是否有父類,是否爲抽象類,是否實現了接口或父類要求實現的方法等
- 字節碼驗證,最複雜的一步,數據流和控制流分析。
- 符號引用驗證,解析階段發生,將符號引用轉換爲直接引用。
準備
爲類變量賦初始值,但並不是爲其賦真正的值,比如:
public static int a = 1;
該步爲a在方法區分配空間,並賦值爲0,特殊的final:
public static final int a = 1;
則該步將直接給a賦值爲1。
解析:
符號引用:以一組符號來定位所引用的目標。
直接引用:直接指向目標的指針,相對偏移量或者能間接定位到目標的句柄。
針對類或接口,字段,方法,接口方法四類符號進行解析,將符號引用轉換爲直接引用。
初始化:
以下四種方式會觸發類的初始化:
- 使用new,引用類static變量,static方法,除了final修飾的字段和方法。
- 使用reflect進行反射調用
- 父類
- main方法所在的類,啓動類
書中還介紹了類加載器相關內容,其中實例練習也是關於此部分的,就在這記錄下,我學習到的東西吧!
雙親委派模型,即類優先讓其父類加載,一般是以組合關係來複用父類加載器。(我就不上圖了,網上一大把)。Java有三種類加載器:啓動類加載器,擴展類加載器,應用程序類加載器,自定義的類加載器需要繼承應用程序類加載器。
值得一提的是,虛擬機識別類,是根據其加載器和類本身識別的。同一個類,有不同類加載器加載後,他們是不相等的。
雙親委派模型例子:Tomcat,common類庫(其加載器繼承應用程序類加載器),tomcat和所有應用程序公用;server類庫,只能被tomcat使用;shared類庫只能被所有應用程序使用,禁止tomcat使用;WEB-INF類庫被特定的應用程序使用。
雙親委派模型的破壞:OSGI,具有熱插拔特性,並非按照雙親委派模型。