簡(jiǎn)潔回答:
- 第一步诺凡,判斷常量池是否能定位類(lèi)的符號(hào)引用说贝,并且檢查這個(gè)符號(hào)引用代表的類(lèi)是否被加載议惰、解析、初始化過(guò)乡恕。如果沒(méi)有則執(zhí)行第一步言询,如果有則執(zhí)行第二步
- 第二步類(lèi)加載和初始化(初次使用),具體可分為加載傲宜、驗(yàn)證运杭、準(zhǔn)備、解析函卒、初始化
- 第三步創(chuàng)建對(duì)象辆憔,具體可分為實(shí)例對(duì)象分配內(nèi)存、賦值、執(zhí)行實(shí)例初始化代碼虱咧、返回引用
詳細(xì)回答
第一步
判斷常量池是否能定位類(lèi)的符號(hào)引用熊榛,并且檢查這個(gè)符號(hào)引用代表的類(lèi)是否被加載、解析彤钟、初始化過(guò)。如果沒(méi)有則執(zhí)行第一步跷叉,如果有則執(zhí)行第二步
第二步逸雹,類(lèi)加載和初始化(初次使用)
如果類(lèi)已經(jīng)被加載過(guò),則不會(huì)執(zhí)行第一步整個(gè)步驟
1. 加載
- 類(lèi)加載器根據(jù)類(lèi)的全限定名來(lái)讀取此類(lèi)的二進(jìn)制字節(jié)流到JVM內(nèi)部云挟,并存儲(chǔ)在運(yùn)行時(shí)內(nèi)存區(qū)的方法區(qū)梆砸,然后將其轉(zhuǎn)換為一個(gè)與目標(biāo)類(lèi)型對(duì)應(yīng)的java.lang.Class對(duì)象實(shí)例
2. 驗(yàn)證
- 格式驗(yàn)證:驗(yàn)證是否符合class文件規(guī)范,比如必須以魔數(shù)0xCAFEBABE開(kāi)頭
- 語(yǔ)義驗(yàn)證:檢查一個(gè)被標(biāo)記為final的類(lèi)型是否包含子類(lèi)园欣;檢查一個(gè)類(lèi)中的final方法是否被子類(lèi)進(jìn)行重寫(xiě)帖世;確保父類(lèi)和子類(lèi)之間沒(méi)有不兼容的一些方法聲明(比如方法簽名相同,但方法的返回值不同)
- 操作驗(yàn)證:在操作數(shù)棧中的數(shù)據(jù)必須進(jìn)行正確的操作沸枯,對(duì)常量池中的各種符號(hào)引用執(zhí)行驗(yàn)證(通常在解析階段執(zhí)行日矫,檢查是否可以通過(guò)符號(hào)引用中描述的全限定名定位到指定類(lèi)型上,以及類(lèi)成員信息的訪問(wèn)修飾符是否允許訪問(wèn)等)
3. 準(zhǔn)備
- 為類(lèi)中的所有靜態(tài)變量/常量分配內(nèi)存空間绑榴,并為其設(shè)置一個(gè)初始值(由于還沒(méi)有產(chǎn)生對(duì)象哪轿,實(shí)例變量不在此操作范圍內(nèi))
public static int value= 1,初始化后的值為 0
public static final int value= 1翔怎,初始化后的值為 1
4. 解析
- 將常量池中的符號(hào)引用轉(zhuǎn)為直接引用(得到類(lèi)或者字段窃诉、方法在內(nèi)存中的指針或者偏移量,以便直接調(diào)用該方法)
符號(hào)引用:比如我們規(guī)定了json字符串赤套,"{}"表示對(duì)象飘痛,"[]"表示數(shù)組,"{}"和"[]"就相當(dāng)于符號(hào)引用容握。在JVM中符號(hào)引用是用一組符號(hào)描述所引用的目標(biāo)宣脉,比如用0x4000聲明這是一個(gè)枚舉類(lèi)型
直接引用:內(nèi)存地址(指針/偏移量/句柄)
5. 初始化(先父類(lèi),再子類(lèi))
- 執(zhí)行類(lèi)構(gòu)造器 init 方法剔氏,init方法包含 為靜態(tài)變量賦值脖旱、執(zhí)行static代碼塊
第三步,創(chuàng)建對(duì)象
1. 在堆區(qū)為實(shí)例對(duì)象分配內(nèi)存
- 為實(shí)例變量分配內(nèi)存(包括本類(lèi)和父類(lèi))介蛉,但不包括任何靜態(tài)變量
2. 對(duì)實(shí)例變量賦默認(rèn)值
- 將方法區(qū)內(nèi)對(duì)實(shí)例變量的定義拷貝一份到堆區(qū)萌庆,然后賦默認(rèn)值
3. 執(zhí)行實(shí)例初始化代碼
- 先初始化父類(lèi)再初始化子類(lèi),初始化時(shí)先執(zhí)行非靜態(tài)代碼塊(包括非靜態(tài)初始化塊币旧,非靜態(tài)屬性)再執(zhí)行構(gòu)造方法
非靜態(tài)代碼塊也叫做實(shí)例代碼塊
4. 將堆區(qū)對(duì)象的地址賦值給棧區(qū)的引用變量
- 有類(lèi)似于Child c = new Child()形式的引用践险,將堆區(qū)對(duì)象的地址賦值給棧區(qū)的引用變量c