在說具體的內容以前,咱們須要先理解一個概念,數據格式。java
所謂數據格式,就是數據按照約定好的格式寫。數組
好比:bash
字節碼的數據格式就是嚴格規定好,前0-3字節 是魔數,4-5字節 次版本號,6-7版本號,8-9常量池數量等。數據結構
爲何0-3必定是魔術,4-7是版本號,由於這就是約定好的,你按照這個格式寫,我按照這個格式讀。jvm
{} 表明對象,[]表明數組,爲何,由於咱們就這麼約定。函數
咱們開發中可能約定, I 開頭表明接口, impl結尾 表明實現類,等等。都是一種約定好的規則。ui
這裏說一下個人理解spa
首先:JVM 和 class 都有屬於本身的數據結構
其次:class文件在被加載到jvm內存中時候,JVM根據class文件的數據結構規則,
拆分讀取class文件,而後把對應的數據放入JVM中
複製代碼
加載階段完成後,虛擬機外部的二進制字節流就按照虛擬機所需的格式存儲在方法區之中。code
知乎傳送門cdn
class字節碼的數據結構從前至後,包括 魔/版本/常量池/訪問標誌/類索引/父類索引/接口索引/字段表/方法表/屬性表
而常量池包括:
字面量
符號引用
類加載以後,常量池的內容會進入運行時常量池,這時候裏面的數據也許還保持着符號引用。
(由於解析的時機由JVM本身設定)
若是在虛擬機棧的 棧幀中,我準備調用 main() 函數,那麼會經過棧幀中持有的動態鏈接,找到運行時常量池,
而後找到main函數的常量 好比 #2 ,若是這個常量沒有被解析過,那麼就經過這個常量進行解析過程,
其中包括,經過常量 找到 類名 和 nameAndType,經過 nameAndType 找到方法名和返回值。
這時候 我手裏有 類名/方法名/方法返回值,下一步,我經過類名和方法名,經過JVM記錄的方法列表,找到對應的方法體。
而這個方法體其實是一段內存地址,那麼這時候我就把這段內存地址複製給 #2,而且給 #2設定一個已經解析的 flag。
這樣就完成了 符號引用到直接引用的過程。
複製代碼
虛擬機加載經歷 加載--驗證--準備--解析--初始化--使用--卸載,《深刻理解Java虛擬機》-周志明,書中說,加載過程當中也能夠驗證,我以爲沒問題,好比,我讀取了class的前四個字段,加載進來了,而後就直接驗證,看看魔數對不對,不對我就再也不加載。這個很OK。
好比魔數對了,那麼我再加載四個字節,而後驗證,看看版本號能不能被JVM解釋,不能就報錯,也很OK。