這篇文章主要介紹“Java類加載機(jī)制有哪些內(nèi)容”,在日常操作中,相信很多人在Java類加載機(jī)制有哪些內(nèi)容問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Java類加載機(jī)制有哪些內(nèi)容”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
創(chuàng)新互聯(lián)建站于2013年成立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目做網(wǎng)站、網(wǎng)站設(shè)計(jì)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元鳳慶做網(wǎng)站,已為上家服務(wù),為鳳慶各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18980820575一:前言
Java語(yǔ)言的類型可以分為兩大類:基本類型和引用類型。
基本類型包括byte,short,int,long,float,double,boolean,char。
引用類型包括類,接口,數(shù)組類和泛型參數(shù)。由于泛型參數(shù)會(huì)在編譯過(guò)程中被擦除,因此Java虛擬機(jī)實(shí)際上只有前三種。在類,接口和數(shù)組類中,數(shù)組類是由Java虛擬機(jī)直接生成的,其它兩種則有對(duì)應(yīng)的字節(jié)流。
二:加載
1.加載,就是查找字節(jié)流,并且據(jù)此生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象的過(guò)程。注意這里字節(jié)流不一定非得要從一個(gè)Class文件獲取,這里既可以從ZIP包中讀?。ū热鐝膉ar包和war包中讀?。部梢栽谶\(yùn)行時(shí)計(jì)算生成(動(dòng)態(tài)代理),也可以由其它文件生成(比如將JSP文件轉(zhuǎn)換成對(duì)應(yīng)的Class類)。加載的信息存儲(chǔ)在JVM的方法區(qū)。
2.對(duì)于數(shù)組類來(lái)說(shuō),它并沒(méi)有對(duì)應(yīng)的字節(jié)流,而是由Java虛擬機(jī)直接生成的。對(duì)于其它的類來(lái)說(shuō),Java虛擬機(jī)則需要借助類加載器來(lái)完成查找字節(jié)流的過(guò)程。
3.類加載器有兩種,一種是啟動(dòng)類加載器,其它的類加載器都是java.lang.ClassLoader的子類。啟動(dòng)類加載器是由C++實(shí)現(xiàn)的,沒(méi)有對(duì)應(yīng)的Java對(duì)象,因此在Java中只能用null代替。除了啟動(dòng)類加載器之外,另外兩個(gè)重要的類加載器是擴(kuò)展類加載器和應(yīng)用類加載器,均由Java核心類庫(kù)提供。 啟動(dòng)類加載器加載最為基礎(chǔ),最為重要的類,如JRE的lib目錄下jar包中的類;擴(kuò)展類加載器的父類是啟動(dòng)類加載器,它負(fù)責(zé)加載相對(duì)次要,但又通用的類,如JRE的lib/ext目錄下jar包中的類;應(yīng)用類加載器的父類加載器則是擴(kuò)展類加載器,它負(fù)責(zé)加載應(yīng)用程序路徑下的類。
4.JVM通過(guò)雙親委派模型進(jìn)行類的加載,當(dāng)然我們也可以通過(guò)繼承java.lang.ClassLoader實(shí)現(xiàn)自定義的類加載器。當(dāng)一個(gè)類加載器收到類加載任務(wù),會(huì)先交給其父類加載器去完成,因此最終加載任務(wù)都會(huì)傳遞到頂層的啟動(dòng)類加載器,只有當(dāng)父類加載器無(wú)法完成加載任務(wù)時(shí),才會(huì)嘗試執(zhí)行加載任務(wù)。
采用雙親委派的一個(gè)好處是比如加載位于rt.jar包中的類java.lang.Object,不管是哪個(gè)加載器加載這個(gè)類,最終都是委托給頂層的啟動(dòng)類加載器進(jìn)行加載,這樣就保證了使用不同的類加載器最終得到的都是同樣一個(gè)Object對(duì)象。
三:鏈接
鏈接,是指將創(chuàng)建成的類合并至Java虛擬機(jī)中,使之能夠執(zhí)行的過(guò)程。它分為驗(yàn)證,準(zhǔn)備和解析三個(gè)階段。
1.驗(yàn)證
該階段的目的在于確保被加載類能夠滿足Java虛擬機(jī)的約束條件。
2.準(zhǔn)備
該階段的目的是為被加載類的靜態(tài)字段分配內(nèi)存,即在方法區(qū)中分配這些變量所使用的內(nèi)存空間。Java代碼中對(duì)靜態(tài)字段的具體初始化,則會(huì)在稍后的初始化階段中進(jìn)行。
3.解析
在class文件被加載至Java虛擬機(jī)前,這個(gè)類無(wú)法知道其它類及其方法,字段所對(duì)應(yīng)的具體地址。甚至不知道自己方法,字段的地址。因此,每當(dāng)需要引用這些成員時(shí),
Java編譯器會(huì)生成一個(gè)符號(hào)引用。在運(yùn)行階段,這個(gè)符號(hào)引用一般能夠無(wú)歧義地定位到具體目標(biāo)上。解析階段的目的,正是將這些符號(hào)引用解析為實(shí)際引用。如果符號(hào)引用
指向一個(gè)未被加載的類,或者未被加載類的字段或方法,那么解析將觸發(fā)這個(gè)類的加載。
四:初始化
1.初始化階段是類加載最后一個(gè)階段,前面的類加載階段之后,除了在加載階段可以自定義類加載器以外,其它操作都由JVM主導(dǎo)。到了初始階段,才開(kāi)始真正執(zhí)行類中定義的Java程序代碼。
2.在 Java 代碼中,如果要初始化一個(gè)靜態(tài)字段,我們可以在聲明時(shí)直接賦值,也可以在靜態(tài)代碼塊中對(duì)其賦值。
如果直接賦值的靜態(tài)字段被 final 所修飾,并且它的類型是基本類型或字符串時(shí),那么該字段便會(huì)被 Java 編譯器標(biāo)記成常量值(ConstantValue),其初始化直接由 Java 虛擬機(jī)完成。除此之外的直接賦值操作,以及所有靜態(tài)代碼塊中的代碼,則會(huì)被 Java 編譯器置于同一方法中,并把它命名為 < clinit >。
類加載的最后一步是初始化,便是為標(biāo)記為常量值的字段賦值,以及執(zhí)行 < clinit > 方法的過(guò)程。Java 虛擬機(jī)會(huì)通過(guò)加鎖來(lái)確保類的 < clinit > 方法僅被執(zhí)行一次。
只有當(dāng)初始化完成之后,類才正式成為可執(zhí)行的狀態(tài)。
3.JVM 規(guī)范枚舉類的初始化被觸發(fā)的情況:
a.當(dāng)虛擬機(jī)啟動(dòng)時(shí),初始化用戶指定的主類;
b.當(dāng)遇到用以新建目標(biāo)類實(shí)例的 new 指令時(shí),初始化 new 指令的目標(biāo)類;
c.當(dāng)遇到調(diào)用靜態(tài)方法的指令時(shí),初始化該靜態(tài)方法所在的類;
d.當(dāng)遇到訪問(wèn)靜態(tài)字段的指令時(shí),初始化該靜態(tài)字段所在的類;
e.子類的初始化會(huì)觸發(fā)父類的初始化;
f.如果一個(gè)接口定義了 default 方法,那么直接實(shí)現(xiàn)或者間接實(shí)現(xiàn)該接口的類的初始化,會(huì)觸發(fā)該接口的初始化;
j.使用反射 API 對(duì)某個(gè)類進(jìn)行反射調(diào)用時(shí),初始化這個(gè)類;
h.當(dāng)初次調(diào)用 MethodHandle 實(shí)例時(shí),初始化該 MethodHandle 指向的方法所在的類。
到此,關(guān)于“Java類加載機(jī)制有哪些內(nèi)容”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!