Java類初始化條件java
(1)類加載的時機:數組
a) 生命週期:加載,驗證,準備,解析,初始化,使用,卸載。數據結構
b) 5個肯定的加載順序,驗證,準備,初始化,卸載。函數
c) 初始化的條件(有且僅有的四個條件):對象
i. 遇到new,getstatic,putstatic,invokestatic字節碼時,若未初始化,觸發。繼承
ii. 反射調用的時候,若沒有初始化,觸發;遞歸
iii. 初始化類時,若父類未初始化,觸發;接口
iv. 虛擬機啓動是,主類(含有main方法)觸發初始化;生命週期
要點:內存
(1)子類中調用父類的靜態字段,只會觸發父類的初始化,不會觸發子類的初始化;
(2)New一個類的數組的時候,不會觸發類的初始化階段;
(3)類調用static final常量,不會觸發類的初始化。
特列:
接口的初始化和類的初始化稍有不一樣,接口中沒有static代碼塊。區別在於類初始化條件第三條的父類初始化,如果接口則不須要初始化接口的時候初始化父類接口,只有當引用父類的時候纔會進行初始化。
Java類加載過程
(1)加載:
a) 根據類的權限定名獲取二進制字節流;
b) 將上述動做獲取的字節流中表明的靜態存儲結果轉化爲運行是數據結構;
c) 在java堆中生成一個class對象,做爲數據訪問入口。
(2)驗證(確認字節流信息符合虛擬機要求):
a) 文件格式驗證:確保獲取的二進制字節流可以正確解析,並存儲於方法區中;
b) 元數據驗證:進行語義分析,確保符合java語言規範;
c) 字節碼驗證:主要進行數據流和控制流分析;
d) 符號引用驗證:確保解析階段正常運行,若沒法經過驗證,拋出異常。
(3)準備(正式爲變量分配內存並設置類變量初始值的階段)
初始化的部分只是變量,一般狀況下都爲零值。
若是具備final修飾,則初始化爲指定的值。
(4)解析
將常量池裏面的符號引用轉化爲直接引用的過程
a) 類或者接口的解析:
i. 若不是數組類型,傳遞全限定名給當前類的加載器;
ii. 如果數組類型,而且爲對象元素,相似Integer類,則按照第一點加載元素類型,如果integer類,直接生成維度堆
iii. 上述步驟沒有異常,則進行符號引用驗證,確認訪問權限。
b) 字段解析:
ⅰ. 自己具備簡單名和字段描述都與目標相匹配的字段,則返回;
ⅱ.不然,如果有接口實現,從上往下遞歸搜索,找到則返回;
ⅲ.不然,按照繼承關係,從上往下遞歸搜索,找到則返回;不然拋出異常;
c) 類方法解析
和字段解釋稍微有點不一樣的地方是,找方法時先找父類,而不是接口。其餘邏輯就是找到匹配的則返回。這裏要判斷自己是否爲抽象類,由於匹配到的方法多是實現的接口列表以及父接口的方法;不然NOsuchmethod異常
d) 接口方法解析
與類方法的過程是同樣的。區別就是不須要斷定是否是實現過該方法。
(5)初始化
這個階段是開始執行java代碼的時候。這個階段是執行構造函數的過程。
Java類加載器
Java裏面的三類加載器:啓動類加載器,擴展類加載器,應用程序類加載器。推薦使用的雙親委派模型。每一次的加載都要求先把這個加載請求發到父類加載器進行加載,全部的加載請求最終都會傳給啓動類加載器,只有當父類加載器反饋回來不能完成加載請求,則嘗試本身加載。
OSGI 則是破壞雙親委派模型的案例之一。