摘要:二驗證驗證主要是為了確保文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機的自身安全。五初始化類的初始化階段是類加載過程的最后一步,該階段才真正開始執行類中定義的程序代碼或者說是字節碼。
關注我,每天三分鐘,帶你輕松掌握一個Java相關知識點。
虛擬機(JVM)經常出現在我們面試中,但是工作中卻很少遇到,導致很多同學沒有去了解過。其實除了應付面試,作為java程序員,了解我們寫的java程序為什么能運行起來也是很有必要的。
我準備在接下來的一系列文章中,整理虛擬機的相關運行機制,讓同學們對虛擬機有個整體的概念。(聲明一下,文章內容基于周志明的《深入理解Java虛擬機》,也非常推薦同學們去讀這本書)
先說一個知識點,咱們寫的代碼,都是.java文件,但是虛擬機只認.class文件,那么誰做的這個部分的轉換呢?
看到JDK中Tools&Tool APIs了嗎,其中的javac干了這件事。
好了我們回到正題,虛擬機是怎么把class文件加載到內存中并且執行使用的呢?
一個class從進入內存到被提出內存,總共經歷了加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸載(Unloading)這7個階段,哪這7個階段都干了啥呢?
一、加載
這個階段虛擬機主要完成了3件事:
1.通過一個類的全限定名來獲取定義此類的二進制字節流。
2.將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構。
3.在內存中生成一個代表這個類的java.lang.Class對象,作為方法去這個類的各種數據的訪問入口。
我們可以看到,通過加載,class文件從目標路徑轉到虛擬機的方法區中,并且clss文件中的數據能被其他人訪問了。
二、驗證
驗證主要是為了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機的自身安全。
驗證階段包含4個階段的檢驗動作:
1.文件格式檢驗,就是說傳過來的字節流一定要符合Class文件的格式規范。
2.元數據驗證,這個是對解析出的字節碼進行語義驗證,以保證其信息符合Java語言規范。
3.字節碼驗證,這個階段將對類的方法體進行校驗分析,保證被校驗類方法在運行的時候,不會危害虛擬機。
4.符號引用驗證,這個階段校驗發生在虛擬機將符號引用轉換為直接引用的時候,也就是在解析階段發生的。
有的同學看到這可能要疑問了,你這驗證的4個步驟,都涉及了后面的流程,難道這些流程不是順序的嗎?
其實加載、驗證、準備、初始化和卸載這5個階段的順序是確定的,類的加載過程必須按照這個中順序開始,但是開始不代表進行或者完成,就是這些階段被調用的順序是確定的,但是他們在什么時候結束是不一定的,這些階段通常都是互相交叉混合進行的。寶寶起名網
這里面解析階段的執行順序是不確定的,這是為了支持java的運行時綁定(多態就是動態綁定的體現,編譯時不知道變量指向的是父類還是子類,只有在運行時才去找時機類型的方法表,確定方法簽名調用)。
三、準備
準備階段的工作是給類變量分配內存并使之類變量初始值的階段。
這里說明一個概念:
類變量:類變量是Class級別的變量,通常用static修飾,它是在類層面共享的變量。
實例變量:實例變量是跟著對象走的,每new一個對象,就有一套類變量。
public static int value = 123;
這句在準備階段,就會給變量value賦值為0,而不是123 。這就是準備階段干的工作,這也是你為什么可以不給實例變量賦值初值的原因(而局部變量必須賦初值以后會解釋,這也跟虛擬機有關)
四、解析
解析階段是虛擬機常量池內的符號引用替換為直接引用的過程。
怎么理解呢?你可以把這個符號引用當做虛擬機和class文件約定好的黑話,不管哪個虛擬機來了,都要用一套黑話他們才能交流。而他們說了什么呢,他們說了目標對象的各種信息,這些信息在各個虛擬機里描述都不一樣,你可以把虛擬機理解為各個殺手組織,他們再收到同一句黑話描述暗殺對象的時候,在組織內部對對象的描述都不一樣。
直接引用就是殺手組織內部翻譯的黑話了,翻譯出來的內容一般都包括目標對象的指針、相對偏移量或是一個能間接定位到目標的句柄。直接引用是與虛擬機內存布局實現相關的,同一個符號引用在不同虛擬機實例上翻譯出來的直接引用一般不會相同,如果有了直接引用,那引用的目標必定已經在內存中存在。
五、初始化
類的初始化階段是類加載過程的最后一步,該階段才真正開始執行類中定義的Java程序代碼(或者說是字節碼)。
對于初始化階段,虛擬機規范有且僅有5種情況必須立即對類進行初始化:
1.遇到new(使用new關鍵字實例化對象)、getstatic(獲取一個類的靜態字段,final修飾符修飾的靜態字段除外)、putstatic(設置一個類的靜態字段,final修飾符修飾的靜態字段除外)和invokestatic(調用一個類的靜態方法)這4條字節碼指令時,如果類還沒有初始化,則必須首先對其初始化
2.使用java.lang.reflect包中的方法對類進行反射調用時,如果類還沒有初始化,則必須首先對其初始化
3.當初始化一個類時,如果其父類還沒有初始化,則必須首先初始化其父類
4.當虛擬機啟動時,需要指定一個主類(main方法所在的類),虛擬機會首選初始化這個主類
5.當使用JDK1.7的動態語言支持時,如果一個java.lang.invoke.MethodHandle實例最后的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且這個方法句柄所對應的類沒有進行過初始化,則需要先觸發其初始化。
以上就是今天的知識點,各位小伙伴get到嗎?創作不易,望各位多多點贊收藏,有什么建議可以留言告訴我,我會積極采納!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/75282.html
摘要:最終形成可以被虛擬機最直接使用的類型的過程就是虛擬機的類加載機制。即重寫一個類加載器的方法驗證驗證是連接階段的第一步,這一階段的目的是為了確保文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。 《深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版》讀書筆記與常見相關面試題總結 本節常見面試題(推薦帶著問題閱讀,問題答案在文中都有提到): 簡單說說類加載過...
摘要:實現這個口號的就是可以運行在不同平臺上的虛擬機和與平臺無關的字節碼。類加載過程加載加載是類加載的第一個階段,虛擬機要完成以下三個過程通過類的全限定名獲取定義此類的二進制字節流。驗證目的是確保文件字節流信息符合虛擬機的要求。 引言 我們知道java代碼編譯后生成的是字節碼,那虛擬機是如何加載這些class字節碼文件的呢?加載之后又是如何進行方法調用的呢? 一 類文件結構 無關性基石 ja...
摘要:虛擬機為了保證一個類的方法在多線程環境中被正確地加鎖同步。但啟動類加載器不可能認識這些代碼。實現模塊化熱部署的關鍵則是它的自定義類加載器機制的實現。 概念區分:加載、類加載、類加載器 類加載是一個過程。 加載(Loading)是類加載這一個過程的階段。 類加載器是ClassLoader類或其子類。 本文中的類的描述都包括了類和接口的可能性,因為每個Class文件都有可能代表J...
閱讀 783·2023-04-25 17:33
閱讀 3636·2021-07-29 14:49
閱讀 2487·2019-08-30 15:53
閱讀 3440·2019-08-29 16:27
閱讀 2007·2019-08-29 16:11
閱讀 1036·2019-08-29 14:17
閱讀 2443·2019-08-29 13:47
閱讀 2023·2019-08-29 13:28