詳解JAVA類加載機(jī)制(推薦)
JAVA源碼編譯由三個(gè)過(guò)程組成:
1、源碼編譯機(jī)制。
2、類加載機(jī)制
3、類執(zhí)行機(jī)制
我們這里主要介紹編譯和類加載這兩種機(jī)制。
一、源碼編譯
代碼編譯由JAVA源碼編譯器來(lái)完成。主要是將源碼編譯成字節(jié)碼文件(class文件)。字節(jié)碼文件格式主要分為兩部分:常量池和方法字節(jié)碼。
二、類加載
類的生命周期是從被加載到虛擬機(jī)內(nèi)存中開(kāi)始,到卸載出內(nèi)存結(jié)束。過(guò)程共有七個(gè)階段,其中到初始化之前的都是屬于類加載的部分
加載----驗(yàn)證----準(zhǔn)備----解析-----初始化----使用-----卸載
系統(tǒng)可能在第一次使用某個(gè)類時(shí)加載該類,也可能采用預(yù)加載機(jī)制來(lái)加載某個(gè)類,當(dāng)運(yùn)行某個(gè)java程序時(shí),會(huì)啟動(dòng)一個(gè)java虛擬機(jī)進(jìn)程,兩次運(yùn)行的java程序處于兩個(gè)不同的JVM進(jìn)程中,兩個(gè)jvm之間并不會(huì)共享數(shù)據(jù)。
1、加載階段
這個(gè)流程中的加載是類加載機(jī)制中的一個(gè)階段,這兩個(gè)概念不要混淆,這個(gè)階段需要完成的事情有:
1)通過(guò)一個(gè)類的全限定名來(lái)獲取定義此類的二進(jìn)制字節(jié)流。
2)將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
3)在java堆中生成一個(gè)代表這個(gè)類的Class對(duì)象,作為訪問(wèn)方法區(qū)中這些數(shù)據(jù)的入口。
由于第一點(diǎn)沒(méi)有指明從哪里獲取以及怎樣獲取類的二進(jìn)制字節(jié)流,所以這一塊區(qū)域留給我開(kāi)發(fā)者很大的發(fā)揮空間。這個(gè)我在后面的類加載器中在進(jìn)行介紹。
2、準(zhǔn)備階段
這個(gè)階段正式為類變量(被static修飾的變量)分配內(nèi)存并設(shè)置類變量初始值,這個(gè)內(nèi)存分配是發(fā)生在方法區(qū)中。
1、注意這里并沒(méi)有對(duì)實(shí)例變量進(jìn)行內(nèi)存分配,實(shí)例變量將會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一起分配在JAVA堆中。
2、這里設(shè)置的初始值,通常是指數(shù)據(jù)類型的零值。
private static int a = 3;
這個(gè)類變量a在準(zhǔn)備階段后的值是0,將3賦值給變量a是發(fā)生在初始化階段。
3、初始化階段
初始化是類加載機(jī)制的最后一步,這個(gè)時(shí)候才正真開(kāi)始執(zhí)行類中定義的JAVA程序代碼。在前面準(zhǔn)備階段,類變量已經(jīng)賦過(guò)一次系統(tǒng)要求的初始值,在初始化階段最重要的事情就是對(duì)類變量進(jìn)行初始化,關(guān)注的重點(diǎn)是父子類之間各類資源初始化的順序。
java類中對(duì)類變量指定初始值有兩種方式:1、聲明類變量時(shí)指定初始值;2、使用靜態(tài)初始化塊為類變量指定初始值。
初始化的時(shí)機(jī)
1)創(chuàng)建類實(shí)例的時(shí)候,分別有:1、使用new關(guān)鍵字創(chuàng)建實(shí)例;2、通過(guò)反射創(chuàng)建實(shí)例;3、通過(guò)反序列化方式創(chuàng)建實(shí)例。
new Test(); Class.forName(“com.mengdd.Test”);
2)調(diào)用某個(gè)類的類方法(靜態(tài)方法)
Test.doSomething();
3)訪問(wèn)某個(gè)類或接口的類變量,或?yàn)樵擃愖兞抠x值。
int b=Test.a; Test.a=b;
4)初始化某個(gè)類的子類。當(dāng)初始化子類的時(shí)候,該子類的所有父類都會(huì)被初始化。
5)直接使用java.exe命令來(lái)運(yùn)行某個(gè)主類。
除了上面幾種方式會(huì)自動(dòng)初始化一個(gè)類,其他訪問(wèn)類的方式都稱不會(huì)觸發(fā)類的初始化,稱為被動(dòng)引用。
1、子類引用父類的靜態(tài)變量,不會(huì)導(dǎo)致子類初始化。
public class SupClass { public static int a = 123; static { System.out.println("supclass init"); } } public class SubClass extends SupClass { static { System.out.println("subclass init"); } } public class Test { public static void main(String[] args) { System.out.println(SubClass.a); } }
執(zhí)行結(jié)果:
supclass init
123
2、通過(guò)數(shù)組定義引用類,不會(huì)觸發(fā)此類的初始化
public class SupClass { public static int a = 123; static { System.out.println("supclass init"); } } public class Test { public static void main(String[] args) { SupClass[] spc = new SupClass[10]; } }
執(zhí)行結(jié)果:
3、引用常量時(shí),不會(huì)觸發(fā)該類的初始化
public class ConstClass { public static final String A= "MIGU"; static { System.out.println("ConstCLass init"); } } public class TestMain { public static void main(String[] args) { System.out.println(ConstClass.A); } }
執(zhí)行結(jié)果:
MIGU
用final修飾某個(gè)類變量時(shí),它的值在編譯時(shí)就已經(jīng)確定好放入常量池了,所以在訪問(wèn)該類變量時(shí),等于直接從常量池中獲取,并沒(méi)有初始化該類。
初始化的步驟
1、如果該類還沒(méi)有加載和連接,則程序先加載該類并連接。
2、如果該類的直接父類沒(méi)有加載,則先初始化其直接父類。
3、如果類中有初始化語(yǔ)句,則系統(tǒng)依次執(zhí)行這些初始化語(yǔ)句。
在第二個(gè)步驟中,如果直接父類又有直接父類,則系統(tǒng)會(huì)再次重復(fù)這三個(gè)步驟來(lái)初始化這個(gè)父類,依次類推,JVM最先初始化的總是java.lang.Object類。當(dāng)程序主動(dòng)使用任何一個(gè)類時(shí),系統(tǒng)會(huì)保證該類以及所有的父類都會(huì)被初始化。
以上所述是小編給大家介紹的JAVA類加載機(jī)制(推薦),希望對(duì)大家有所幫助!
相關(guān)文章
Spring整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案
這篇文章主要介紹了Spring 整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10java數(shù)字和中文算數(shù)驗(yàn)證碼的實(shí)現(xiàn)
這篇文章主要介紹了java數(shù)字和中文算數(shù)驗(yàn)證碼的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Hibernate映射解析之關(guān)聯(lián)映射詳解
所謂關(guān)聯(lián)映射就是將關(guān)聯(lián)關(guān)系映射到數(shù)據(jù)庫(kù)里,在對(duì)象模型中就是一個(gè)或多個(gè)引用。下面這篇文章詳細(xì)的給大家介紹了Hibernate映射解析之關(guān)聯(lián)映射的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-02-02nacos在liunx系統(tǒng)中啟動(dòng)成功瀏覽器卻訪問(wèn)不了的解決方法
在linux下搭建nacos,現(xiàn)在想要啟動(dòng),訪問(wèn)nacos頁(yè)面,訪問(wèn)不了,所以本文小編將給大家介紹nacos在liunx系統(tǒng)中啟動(dòng)成功,瀏覽器卻訪問(wèn)不了?全面的解決辦法,需要的朋友可以參考下2023-09-09hotspot解析jdk1.8?Unsafe類park和unpark方法使用
這篇文章主要為大家介紹了hotspot解析jdk1.8?Unsafe類park和unpark方法使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01