我們知道,我們寫(xiě)的java代碼保存的格式是 .java, java文件被編譯后會(huì)轉(zhuǎn)換為字節(jié)碼,字節(jié)碼可以在任何平臺(tái)通過(guò)java虛擬機(jī)來(lái)運(yùn)行,這也是java能夠跨平臺(tái)的原因。
創(chuàng)新互聯(lián)公司是專(zhuān)業(yè)的灤南網(wǎng)站建設(shè)公司,灤南接單;提供網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專(zhuān)業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行灤南網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專(zhuān)業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專(zhuān)業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!那JVM是如何來(lái)讓我們寫(xiě)的java文件運(yùn)行的呢? 這個(gè)問(wèn)題通常的問(wèn)法好像是:類(lèi)是如何被加載的。
記得第一次遇見(jiàn)這個(gè)問(wèn)題的時(shí)候,同學(xué)給我的回答是:
1.虛擬機(jī)會(huì)加載JDK里類(lèi)的核心包
2.虛擬機(jī)會(huì)加載JDK里類(lèi)的擴(kuò)展包
3.虛擬機(jī)會(huì)加載JDK里類(lèi)的系統(tǒng)包
4.虛擬機(jī)再會(huì)加載我們寫(xiě)好的java類(lèi)。
初學(xué)的時(shí)候,大家都這么說(shuō),好像也沒(méi)發(fā)現(xiàn)什么錯(cuò)。 最近在瀏覽一些博客時(shí)看到一些更為詳細(xì)的講解,如java類(lèi)加載全過(guò)程,該博文有一萬(wàn)多的點(diǎn)擊,但感覺(jué)還是講得不夠詳細(xì),說(shuō)了類(lèi)的加載過(guò)程有哪些,但沒(méi)有詳細(xì)的展開(kāi),說(shuō)了一些類(lèi)初始化的細(xì)節(jié)。 在翻讀《深入理解Java虛擬機(jī)》209-235頁(yè)后,總結(jié)了其內(nèi)容,談?wù)勛约簩?duì)該部分的理解吧。
希望大家看了之后更能理解JVM的工作原理和java類(lèi)的生產(chǎn)過(guò)程(類(lèi)加載的過(guò)程);
類(lèi)從被加載到虛擬機(jī)類(lèi)存中開(kāi)始,到被卸載出內(nèi)存為止,它的整個(gè)生命周期包括
加載 → 驗(yàn)證 → 準(zhǔn)備 → 解析 → 初始化 → 使用 → 卸載 7個(gè)部分、
下面我就來(lái)詳細(xì)的說(shuō)說(shuō)每個(gè)部分的詳細(xì)過(guò)程,再補(bǔ)充一下雙親委派模型。
再次之前我想補(bǔ)充一個(gè)名詞解釋?zhuān)?lèi)加載器:虛擬機(jī)把 實(shí)現(xiàn) 類(lèi)加載階段中的“通過(guò)一個(gè)類(lèi)的全限定名來(lái)獲取描述此類(lèi)的二進(jìn)制字節(jié)流” 這個(gè)過(guò)程的代碼稱(chēng)為類(lèi)加載器
1. 加載
加載只是類(lèi)加載過(guò)程的一個(gè)階段而已,但往往被大家弄成了這就是類(lèi)的加載過(guò)程,所以才有了博文開(kāi)頭時(shí)同學(xué)給我的那個(gè)回答;
希望大家不要混淆出這個(gè)很相似的名詞,從而對(duì)類(lèi)加載有所誤讀。
1.JDK在執(zhí)行程序運(yùn)行命令時(shí)會(huì)去JRE目錄中找到j(luò)vm.dll , 并初始化JVM
這時(shí)會(huì)產(chǎn)生一個(gè)Bootstrap Loader(啟動(dòng)類(lèi)加載器)
2.Bootstrap Loader 自動(dòng)加載 Extended Loader(標(biāo)準(zhǔn)擴(kuò)展類(lèi)加載器)
3.Bootstrap Loader 自動(dòng)加載 AppClass Loader(系統(tǒng)類(lèi)加載器)
4.最后由 AppClass Loader 加載 我們指定(想要運(yùn)行)的 java 類(lèi)
這里可以提一下雙親委派模型加載類(lèi)的方式:
實(shí)現(xiàn)雙親委派的代碼都集中在java.lang.ClassLoader的 loadClass()方法中, 源碼我就不貼出來(lái)了;
其源碼大概意思如下:
1.先檢查此類(lèi)是否被加載過(guò),若沒(méi)有加載則調(diào)用父加載器的loadClass()方法,
2.若父加載器為空,則默認(rèn)使用啟動(dòng)類(lèi)加載器作為父加載器,
3.若父類(lèi)加載失敗,會(huì)拋出一個(gè)異常,然后再調(diào)用自己的findClass()方法來(lái)進(jìn)行加載;
結(jié)合第一步加載可以這么理解,
1.首先要啟動(dòng)→ 啟動(dòng)類(lèi)加載器,這時(shí)會(huì)調(diào)用啟動(dòng)類(lèi)加載器的父加載器,但由于啟動(dòng)類(lèi)加載器時(shí)所有類(lèi)的父加載器,
所以其父加載器為空(相當(dāng)于Object是所有類(lèi)的父類(lèi),這種感腳~),然后它就會(huì)調(diào)用自己的findClass方法來(lái)自啟動(dòng)加載 ;
2.標(biāo)準(zhǔn)擴(kuò)展類(lèi)加載器啟動(dòng)時(shí)就會(huì)借助其父類(lèi) 啟動(dòng)類(lèi)加載器 作為父加載器 來(lái)啟動(dòng)了;
3.系統(tǒng)類(lèi)加載器啟動(dòng)時(shí)就會(huì)借助其父類(lèi) 標(biāo)準(zhǔn)擴(kuò)展類(lèi)加載器 作為父加載器 來(lái)啟動(dòng)了;
4.最后我們編寫(xiě)的普通類(lèi)就會(huì)借助其父類(lèi) 系統(tǒng)類(lèi)加載器 作為父加載器 來(lái)啟動(dòng)了;
2.驗(yàn)證
驗(yàn)證主要分為以下幾個(gè)步驟:文件格式驗(yàn)證->元數(shù)據(jù)驗(yàn)證->字節(jié)碼驗(yàn)證->符號(hào)引用驗(yàn)證
1.文件格式驗(yàn)證:主要是檢查字節(jié)碼的字節(jié)流是否符合Class文件格式的規(guī)范,驗(yàn)證該文件是否能被當(dāng)前的 jvm 所處理,
如果沒(méi)問(wèn)題,字節(jié)里就可以進(jìn)入方法區(qū)進(jìn)行保存了;
2.元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析,保證其描述的內(nèi)容符合java語(yǔ)言的語(yǔ)法規(guī)范,能被java虛擬機(jī)識(shí)別;
3.字節(jié)碼驗(yàn)證:該部分最為復(fù)雜,對(duì)方法體內(nèi)的內(nèi)容進(jìn)行驗(yàn)證,保證代碼在運(yùn)行時(shí)不會(huì)做出什么危害虛擬機(jī)安全的事件;
4.符號(hào)引用驗(yàn)證:來(lái)驗(yàn)證一些引用的真實(shí)性與可行性,比如代碼里面引了其他類(lèi)(符號(hào)中通過(guò)字符串描述的全限定名是否能找到對(duì)應(yīng)的類(lèi)),這里就要去檢測(cè)一下那些來(lái)究竟是否存在;或者說(shuō)代碼中訪(fǎng)問(wèn)了其他類(lèi)的一些屬性,這里就對(duì)那些屬性的可以訪(fǎng)問(wèn)行進(jìn)行了檢驗(yàn)。(這一步將為后面的解析工作打下基礎(chǔ))
多說(shuō)兩句。。。 我覺(jué)得這個(gè)驗(yàn)證就是看class文件符不符合 JVM 的胃口 , 如果不符合 JVM 的胃口的話(huà),無(wú)法完成加載,說(shuō)明你寫(xiě)的代碼 有毒.... 偷笑偷笑
3.準(zhǔn)備
準(zhǔn)備階段會(huì)為類(lèi)變量(指的是靜態(tài)變量,這就是我們常說(shuō)的,靜態(tài)變量/方法 在類(lèi)加載的時(shí)候就執(zhí)行了,通過(guò)類(lèi)名.靜態(tài)**來(lái)調(diào)用)分配內(nèi)存并設(shè)置類(lèi)的初始值; 值得一提的是 如果有以下語(yǔ)句:
public static int i = 123 ;
在準(zhǔn)備階段的初始值是 0 ,而不是 123 , 是因?yàn)榇藭r(shí) 只是分配內(nèi)存空間而已, 并沒(méi)有對(duì) i 進(jìn)行初始化, 真正的對(duì) i 賦值是在 初始化 階段;
4.解析
1.類(lèi)或接口的解析;
2.字段解析;
3.類(lèi)方法解析;
4.接口方法解析;
此部分內(nèi)容涉及 invokedynamic指令,靜態(tài)、動(dòng)態(tài)語(yǔ)音調(diào)用 不做展開(kāi)
如果解析到代碼內(nèi)容有問(wèn)題,解析不通過(guò)將會(huì)拋出異常!
5.初始化
類(lèi)初始化階段是類(lèi)加載過(guò)程中的最后一步,這才是執(zhí)行類(lèi)中定義的java程序代碼(也可以說(shuō)是字節(jié)碼)。
在準(zhǔn)備階段,已經(jīng)為變量賦過(guò)一次系統(tǒng)要求的初始值,到了初始化階段會(huì)根據(jù)程序員的要求出初始化變量賦值。
Java虛擬機(jī)沒(méi)有嚴(yán)格約束什么時(shí)候開(kāi)始類(lèi)加載過(guò)程的第一階段,但嚴(yán)格規(guī)定了有且只有5鐘情況必須立即馬上光速對(duì)類(lèi)進(jìn)行 初始化
當(dāng)然加載、驗(yàn)證、準(zhǔn)備需要在次之前,(解析也可以在初始化以后再開(kāi)始~)
1.遇到new,get static,put static,invoke static這4條字節(jié)碼指令時(shí),假如類(lèi)還沒(méi)進(jìn)行初始化,則馬上對(duì)其進(jìn)行初始化工作。
也就是三種情況:用new實(shí)例化一個(gè)對(duì)象時(shí)、讀取或設(shè)置一個(gè)雷的靜態(tài)字段時(shí)、執(zhí)行靜態(tài)方法時(shí);
2.使用java.lang.reflect.*的方法對(duì)類(lèi)進(jìn)行反射調(diào)用時(shí),如果類(lèi)還沒(méi)有進(jìn)行過(guò)初始化,立即馬上光速對(duì)其進(jìn)行初始化!!!
3.初始化一個(gè)類(lèi)的時(shí)候,如果其父類(lèi)還沒(méi)有被初始化,那么會(huì)先去初始化其父類(lèi);
4.當(dāng) JVM 啟動(dòng)時(shí),用戶(hù)需要指定一個(gè)要執(zhí)行的主類(lèi)(包含static void main(String 【】args)的那個(gè)類(lèi)),則JVM會(huì)先去初始化這個(gè)類(lèi);
5.當(dāng)使用JDK1.7 的動(dòng)態(tài)語(yǔ)言支持時(shí),如果一個(gè)java.lang.invoke.MethodHandle實(shí)力最后的解析結(jié)果為 get static,put static,invoke static 的方法句柄,并且這個(gè)方法句柄所對(duì)應(yīng)的類(lèi)沒(méi)有進(jìn)行過(guò)初始化,則需要先初始化;
小結(jié):
介紹了類(lèi)加載過(guò)程的 加載、驗(yàn)證、準(zhǔn)備、解析、初始化、等5個(gè)階段,以及虛擬機(jī)進(jìn)行了哪些動(dòng)作,簡(jiǎn)單敘述了類(lèi)加載器的工作原理,如果有說(shuō)得不妥當(dāng)?shù)牡胤剑€以請(qǐng)大家批評(píng)指正,多多交流。
標(biāo)題名稱(chēng):java類(lèi)的加載過(guò)程以及類(lèi)加載器的分析-創(chuàng)新互聯(lián)
文章路徑:http://newbst.com/article6/doogog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營(yíng)銷(xiāo)、App開(kāi)發(fā)、標(biāo)簽優(yōu)化、營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、定制網(wǎng)站、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容