Java是一種可以撰寫跨平臺應用軟件的面向對象的程序設計語言。Java 技術具有卓越的通用性、高效性、平臺移植性和安全性,廣泛應用于PC、數據中心、游戲控制臺、科學超級計算機、移動電話和互聯網,同時擁有全球最大的開發(fā)者專業(yè)社群。
給你學習路線:html-css-js-jq-javase-數據庫-jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm
剛剛走出校門的應屆畢業(yè)生程序猿,如果在去尋求一份Java開發(fā)的工作時,你的面試官很有可能一邊看著你的簡歷,一邊漫不經心地問你:了解過Java類的加載過程嗎?
這個時候你一定要注意了,雖然這是一個老生常談的問題,但是這也是一個非常能夠考驗你Java功底的問題。
如果你答好了,這是你應該的;如果你沒答好,那么對不起,面試官心中已經給了你不及格。
小編推薦一個學Java的學習裙【 六五零,五五四,六零七 】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發(fā)工具,很多干貨和技術資料分享!
今天,小編就Java類加載過程這個問題,拋磚引玉,說一下自己的理解,如果有不對的地方,歡迎大家在評論區(qū)指正。
前言
一個Java文件從編碼完成到最終執(zhí)行,一般主要包括兩個過程
編譯
運行
編譯,即把我們寫好的java文件,通過javac命令編譯成字節(jié)碼,也就是我們常說的.class文件。
運行,則是把編譯生成的.class文件交給Java虛擬機(JVM)執(zhí)行。
而我們所說的類加載過程即是指JVM虛擬機把.class文件中類信息加載進內存,并進行解析生成對應的class對象的過程。
舉個通俗點的例子來說,JVM在執(zhí)行某段代碼時,遇到了class A, 然而此時內存中并沒有class A的相關信息,于是JVM就會到相應的class文件中去尋找class A的類信息,并加載進內存中,這就是我們所說的類加載過程。
由此可見,JVM不是一開始就把所有的類都加載進內存中,而是只有第一次遇到某個需要運行的類時才會加載,且只加載一次。
類加載
類加載的過程主要分為三個部分:
加載
鏈接
初始化
而鏈接又可以細分為三個小部分:
驗證
準備
解析
小編推薦一個學Java的學習裙【 六五零,五五四,六零七 】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發(fā)工具,很多干貨和技術資料分享!
加載
簡單來說,加載指的是把class字節(jié)碼文件從各個來源通過類加載器裝載入內存中。
這里有兩個重點:
字節(jié)碼來源。一般的加載來源包括從本地路徑下編譯生成的.class文件,從jar包中的.class文件,從遠程網絡,以及動態(tài)代理實時編譯
類加載器。一般包括啟動類加載器,擴展類加載器,應用類加載器,以及用戶的自定義類加載器。
注:為什么會有自定義類加載器?
一方面是由于java代碼很容易被反編譯,如果需要對自己的代碼加密的話,可以對編譯后的代碼進行加密,然后再通過實現自己的自定義類加載器進行解密,最后再加載。
另一方面也有可能從非標準的來源加載代碼,比如從網絡來源,那就需要自己實現一個類加載器,從指定源進行加載。
驗證
主要是為了保證加載進來的字節(jié)流符合虛擬機規(guī)范,不會造成安全錯誤。
包括對于文件格式的驗證,比如常量中是否有不被支持的常量?文件中是否有不規(guī)范的或者附加的其他信息?
對于元數據的驗證,比如該類是否繼承了被final修飾的類?類中的字段,方法是否與父類沖突?是否出現了不合理的重載?
對于字節(jié)碼的驗證,保證程序語義的合理性,比如要保證類型轉換的合理性。
對于符號引用的驗證,比如校驗符號引用中通過全限定名是否能夠找到對應的類?校驗符號引用中的訪問性(private,public等)是否可被當前類訪問?
準備
主要是為類變量(注意,不是實例變量)分配內存,并且賦予初值。
特別需要注意,初值,不是代碼中具體寫的初始化的值,而是Java虛擬機根據不同變量類型的默認初始值。
比如8種基本類型的初值,默認為0;引用類型的初值則為null;常量的初值即為代碼中設置的值,final static tmp = 456, 那么該階段tmp的初值就是456
解析
將常量池內的符號引用替換為直接引用的過程。
兩個重點:
符號引用。即一個字符串,但是這個字符串給出了一些能夠唯一性識別一個方法,一個變量,一個類的相關信息。
直接引用。可以理解為一個內存地址,或者一個偏移量。比如類方法,類變量的直接引用是指向方法區(qū)的指針;而實例方法,實例變量的直接引用則是從實例的頭指針開始算起到這個實例變量位置的偏移量
舉個例子來說,現在調用方法hello(),這個方法的地址是1234567,那么hello就是符號引用,1234567就是直接引用。
在解析階段,虛擬機會把所有的類名,方法名,字段名這些符號引用替換為具體的內存地址或偏移量,也就是直接引用。
初始化
這個階段主要是對類變量初始化,是執(zhí)行類構造器的過程。
換句話說,只對static修飾的變量或語句進行初始化。
如果初始化一個類的時候,其父類尚未初始化,則優(yōu)先初始化其父類。
如果同時包含多個靜態(tài)變量和靜態(tài)代碼塊,則按照自上而下的順序依次執(zhí)行。
總結
類加載過程只是一個類生命周期的一部分,在其前,有編譯的過程,只有對源代碼編譯之后,才能獲得能夠被虛擬機加載的字節(jié)碼文件;在其后還有具體的類使用過程,當使用完成之后,還會在方法區(qū)垃圾回收的過程中進行卸載。如果想要了解Java類整個生命周期的話,可以自行上網查閱相關資料,這里不再多做贅述。
在面試過程中類加載過程雖然是一個老生常談的問題,但是往往從這個問題還可以衍生出很多其他重要的知識點,已經羅列在下文中,如果大家感興趣的話,可以自行學習,小編也會在之后的文章中,對其中的一些問題進行解答和總結。
小編推薦一個學Java的學習裙【 六五零,五五四,六零七 】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發(fā)工具,很多干貨和技術資料分享!
相關擴展知識點:
Java虛擬機的基本機構?
什么是類加載器?
簡單談一下類加載的雙親委托機制?
普通Java類的類加載過程和Tomcat的類加載過程是否一樣?區(qū)別在哪?
簡單談一下Java堆的垃圾回收機制?
最后,眾程序猿,給個關注,點個贊唄~


