Java是一種可以撰寫跨平臺應(yīng)用軟件的面向?qū)ο蟮某绦蛟O(shè)計語言。Java 技術(shù)具有卓越的通用性返十、高效性、平臺移植性和安全性椭微,廣泛應(yīng)用于PC洞坑、數(shù)據(jù)中心、游戲控制臺蝇率、科學(xué)超級計算機(jī)迟杂、移動電話和互聯(lián)網(wǎng)匈仗,同時擁有全球最大的開發(fā)者專業(yè)社群。
給你學(xué)習(xí)路線:html-css-js-jq-javase-數(shù)據(jù)庫-jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm
剛剛走出校門的應(yīng)屆畢業(yè)生程序猿逢慌,如果在去尋求一份Java開發(fā)的工作時,你的面試官很有可能一邊看著你的簡歷间狂,一邊漫不經(jīng)心地問你:了解過Java類的加載過程嗎攻泼?
這個時候你一定要注意了,雖然這是一個老生常談的問題鉴象,但是這也是一個非常能夠考驗?zāi)鉐ava功底的問題忙菠。
如果你答好了,這是你應(yīng)該的纺弊;如果你沒答好牛欢,那么對不起,面試官心中已經(jīng)給了你不及格淆游。
小編推薦一個學(xué)Java的學(xué)習(xí)裙【 六五零傍睹,五五四,六零七 】犹菱,無論你是大牛還是小白拾稳,是想轉(zhuǎn)行還是想入行都可以來了解一起進(jìn)步一起學(xué)習(xí)!裙內(nèi)有開發(fā)工具腊脱,很多干貨和技術(shù)資料分享访得!
今天,小編就Java類加載過程這個問題陕凹,拋磚引玉悍抑,說一下自己的理解,如果有不對的地方杜耙,歡迎大家在評論區(qū)指正搜骡。
前言
一個Java文件從編碼完成到最終執(zhí)行,一般主要包括兩個過程
編譯
運行
編譯泥技,即把我們寫好的java文件浆兰,通過javac命令編譯成字節(jié)碼,也就是我們常說的.class文件珊豹。
運行簸呈,則是把編譯生成的.class文件交給Java虛擬機(jī)(JVM)執(zhí)行。
而我們所說的類加載過程即是指JVM虛擬機(jī)把.class文件中類信息加載進(jìn)內(nèi)存店茶,并進(jìn)行解析生成對應(yīng)的class對象的過程蜕便。
舉個通俗點的例子來說,JVM在執(zhí)行某段代碼時贩幻,遇到了class A轿腺, 然而此時內(nèi)存中并沒有class A的相關(guān)信息两嘴,于是JVM就會到相應(yīng)的class文件中去尋找class A的類信息,并加載進(jìn)內(nèi)存中族壳,這就是我們所說的類加載過程憔辫。
由此可見,JVM不是一開始就把所有的類都加載進(jìn)內(nèi)存中仿荆,而是只有第一次遇到某個需要運行的類時才會加載贰您,且只加載一次。
類加載
類加載的過程主要分為三個部分:
加載
鏈接
初始化
而鏈接又可以細(xì)分為三個小部分:
驗證
準(zhǔn)備
解析
小編推薦一個學(xué)Java的學(xué)習(xí)裙【 六五零拢操,五五四锦亦,六零七 】,無論你是大牛還是小白令境,是想轉(zhuǎn)行還是想入行都可以來了解一起進(jìn)步一起學(xué)習(xí)杠园!裙內(nèi)有開發(fā)工具,很多干貨和技術(shù)資料分享舔庶!
加載
簡單來說抛蚁,加載指的是把class字節(jié)碼文件從各個來源通過類加載器裝載入內(nèi)存中。
這里有兩個重點:
字節(jié)碼來源栖茉。一般的加載來源包括從本地路徑下編譯生成的.class文件篮绿,從jar包中的.class文件,從遠(yuǎn)程網(wǎng)絡(luò)吕漂,以及動態(tài)代理實時編譯
類加載器亲配。一般包括啟動類加載器,擴(kuò)展類加載器惶凝,應(yīng)用類加載器吼虎,以及用戶的自定義類加載器。
注:為什么會有自定義類加載器苍鲜?
一方面是由于java代碼很容易被反編譯思灰,如果需要對自己的代碼加密的話,可以對編譯后的代碼進(jìn)行加密混滔,然后再通過實現(xiàn)自己的自定義類加載器進(jìn)行解密洒疚,最后再加載。
另一方面也有可能從非標(biāo)準(zhǔn)的來源加載代碼坯屿,比如從網(wǎng)絡(luò)來源油湖,那就需要自己實現(xiàn)一個類加載器,從指定源進(jìn)行加載领跛。
驗證
主要是為了保證加載進(jìn)來的字節(jié)流符合虛擬機(jī)規(guī)范乏德,不會造成安全錯誤。
包括對于文件格式的驗證,比如常量中是否有不被支持的常量喊括?文件中是否有不規(guī)范的或者附加的其他信息胧瓜?
對于元數(shù)據(jù)的驗證,比如該類是否繼承了被final修飾的類郑什?類中的字段府喳,方法是否與父類沖突?是否出現(xiàn)了不合理的重載蘑拯?
對于字節(jié)碼的驗證劫拢,保證程序語義的合理性,比如要保證類型轉(zhuǎn)換的合理性强胰。
對于符號引用的驗證,比如校驗符號引用中通過全限定名是否能夠找到對應(yīng)的類妹沙?校驗符號引用中的訪問性(private偶洋,public等)是否可被當(dāng)前類訪問?
準(zhǔn)備
主要是為類變量(注意距糖,不是實例變量)分配內(nèi)存玄窝,并且賦予初值。
特別需要注意悍引,初值恩脂,不是代碼中具體寫的初始化的值,而是Java虛擬機(jī)根據(jù)不同變量類型的默認(rèn)初始值趣斤。
比如8種基本類型的初值俩块,默認(rèn)為0;引用類型的初值則為null浓领;常量的初值即為代碼中設(shè)置的值玉凯,final static tmp = 456, 那么該階段tmp的初值就是456
解析
將常量池內(nèi)的符號引用替換為直接引用的過程联贩。
兩個重點:
符號引用漫仆。即一個字符串,但是這個字符串給出了一些能夠唯一性識別一個方法泪幌,一個變量盲厌,一個類的相關(guān)信息。
直接引用祸泪÷鸷疲可以理解為一個內(nèi)存地址,或者一個偏移量浴滴。比如類方法拓萌,類變量的直接引用是指向方法區(qū)的指針;而實例方法升略,實例變量的直接引用則是從實例的頭指針開始算起到這個實例變量位置的偏移量
舉個例子來說微王,現(xiàn)在調(diào)用方法hello()屡限,這個方法的地址是1234567,那么hello就是符號引用炕倘,1234567就是直接引用钧大。
在解析階段,虛擬機(jī)會把所有的類名罩旋,方法名啊央,字段名這些符號引用替換為具體的內(nèi)存地址或偏移量,也就是直接引用涨醋。
初始化
這個階段主要是對類變量初始化瓜饥,是執(zhí)行類構(gòu)造器的過程。
換句話說浴骂,只對static修飾的變量或語句進(jìn)行初始化乓土。
如果初始化一個類的時候,其父類尚未初始化溯警,則優(yōu)先初始化其父類趣苏。
如果同時包含多個靜態(tài)變量和靜態(tài)代碼塊,則按照自上而下的順序依次執(zhí)行梯轻。
總結(jié)
類加載過程只是一個類生命周期的一部分食磕,在其前,有編譯的過程喳挑,只有對源代碼編譯之后彬伦,才能獲得能夠被虛擬機(jī)加載的字節(jié)碼文件;在其后還有具體的類使用過程伊诵,當(dāng)使用完成之后媚朦,還會在方法區(qū)垃圾回收的過程中進(jìn)行卸載。如果想要了解Java類整個生命周期的話日戈,可以自行上網(wǎng)查閱相關(guān)資料询张,這里不再多做贅述。
在面試過程中類加載過程雖然是一個老生常談的問題浙炼,但是往往從這個問題還可以衍生出很多其他重要的知識點份氧,已經(jīng)羅列在下文中,如果大家感興趣的話弯屈,可以自行學(xué)習(xí)蜗帜,小編也會在之后的文章中,對其中的一些問題進(jìn)行解答和總結(jié)资厉。
小編推薦一個學(xué)Java的學(xué)習(xí)裙【 六五零厅缺,五五四,六零七 】,無論你是大牛還是小白湘捎,是想轉(zhuǎn)行還是想入行都可以來了解一起進(jìn)步一起學(xué)習(xí)诀豁!裙內(nèi)有開發(fā)工具,很多干貨和技術(shù)資料分享窥妇!
相關(guān)擴(kuò)展知識點:
Java虛擬機(jī)的基本機(jī)構(gòu)舷胜?
什么是類加載器?
簡單談一下類加載的雙親委托機(jī)制活翩?
普通Java類的類加載過程和Tomcat的類加載過程是否一樣烹骨?區(qū)別在哪?
簡單談一下Java堆的垃圾回收機(jī)制材泄?
最后沮焕,眾程序猿,給個關(guān)注拉宗,點個贊唄~