JVM系列1--通過幾個(gè)問題了解JAVA類的加載機(jī)制

一、為什么需要類加載谒拴?類加載做些什么?

jvm執(zhí)行某段代碼的時(shí)候啸驯,需要把類相關(guān)信息加載到j(luò)vm的內(nèi)存中去客扎。
所謂類加載就是jvm把編譯后的class文件中的類信息加載到JVM內(nèi)存,并且生成對(duì)應(yīng)的class對(duì)象的過程

二罚斗、java類什么時(shí)候被加載徙鱼?

jvm并不是一開始就把所有的類都一次性加載到內(nèi)存中去,只有在需要的時(shí)候才會(huì)加載针姿,并且在jvm生命周期中一個(gè)類只會(huì)加載一次袱吆,類被加載過了,就不會(huì)再重復(fù)加載了距淫。所以什么時(shí)候才需要加載java類呢绞绒?

  • 需要加載類的時(shí)機(jī)有以下幾種情況:
  1. 實(shí)例化類的時(shí)候,加載該類
  2. 實(shí)例化子類的時(shí)候榕暇,他未被初始化的父類被加載
  3. 調(diào)用類的靜態(tài)函數(shù)
  4. 調(diào)用類的靜態(tài)變量或賦值
  5. 反射使用class.forname()時(shí)蓬衡,ClassLoader.loadClass()時(shí)
    Class.forName()和ClassLoader.loadClass()區(qū)別:
    Class.forName():將類的.class文件加載到j(luò)vm中之外喻杈,還會(huì)對(duì)類進(jìn)行解釋,執(zhí)行類中的static塊狰晚;
    ClassLoader.loadClass():只干一件事情筒饰,就是將.class文件加載到j(luò)vm中,不會(huì)執(zhí)行static中的內(nèi)容,只有在newInstance才會(huì)去執(zhí)行static塊
  6. java虛擬機(jī)啟動(dòng)的時(shí)候會(huì)加載啟動(dòng)類
  7. 類被加載的時(shí)候壁晒,他的靜態(tài)代碼塊瓷们、靜態(tài)方法及靜態(tài)變量會(huì)被加載,在他進(jìn)行到初始化這個(gè)步驟時(shí)秒咐,如果這個(gè)類的靜態(tài)代碼塊谬晕、靜態(tài)方法或靜態(tài)變量引用到了另一個(gè)類,則這個(gè)被引用的類也會(huì)被加載反镇。

三固蚤、類從哪里加載?

– 從本地系統(tǒng)中直接加載
– 通過網(wǎng)絡(luò)下載.class文件
– 從zip歹茶,jar等歸檔文件中加載.class文件
– 從專有數(shù)據(jù)庫(kù)中提取.class文件
– 將Java源文件動(dòng)態(tài)編譯為.class文件(動(dòng)態(tài)代理什么的)

四夕玩、類加載到哪里去?

編譯后的.class文件的二進(jìn)制數(shù)據(jù)加載到j(luò)vm的方法區(qū)內(nèi)惊豺,生成的Class對(duì)象放到j(luò)vm的堆燎孟,
Class對(duì)象封裝了類的數(shù)據(jù)結(jié)構(gòu),并且向程序員提供了訪問方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)的接口

五尸昧、類加載的時(shí)候做了什么揩页?類加載的流程?

類加載的過程包括了加載烹俗、驗(yàn)證爆侣、準(zhǔn)備、解析幢妄、初始化五個(gè)階段

他們的順序是加載兔仰、驗(yàn)證、準(zhǔn)備蕉鸳、解析乎赴、初始化 或者 加載、驗(yàn)證潮尝、準(zhǔn)備榕吼、初始化、解析
其中加載勉失、驗(yàn)證羹蚣、準(zhǔn)備的順序是固定的,解析和初始化的順序是不一定的戴质,這是為了支持java的運(yùn)行時(shí)綁定

需要注意的是度宦,這里的順序是指按某種順序開始進(jìn)行這一階段的任務(wù)踢匣,而不是串行的,不是開始并完成一項(xiàng)才進(jìn)行下一項(xiàng)的戈抄,這些階段都是交叉混合的進(jìn)行离唬。

  • 加載
    這里的加載是指把class字節(jié)碼文件用類加載器從各個(gè)來(lái)源裝載入內(nèi)存中
    1、通過一個(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è)類的java.lang.Class對(duì)象嫂用,作為對(duì)方法區(qū)中這些數(shù)據(jù)的訪問入口。
  • 驗(yàn)證
    確保被加載的類的正確性丈冬,文件格式驗(yàn)證嘱函、語(yǔ)法語(yǔ)義驗(yàn)證等
  • 準(zhǔn)備
    類的靜態(tài)變量(static修飾的)在方法區(qū)中初始化零值(如0、0L埂蕊、null往弓、false等)
    類的靜態(tài)常量(static final修飾的)在此時(shí)賦予代碼中設(shè)定的值
    常量(final修飾)系統(tǒng)不會(huì)為其賦予默認(rèn)零值
  • 解析
    虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過程
    符號(hào)引用就是一組符號(hào)來(lái)描述目標(biāo),可以是任何字面量蓄氧。
    直接引用就是直接指向目標(biāo)的指針函似、相對(duì)偏移量或一個(gè)間接定位到目標(biāo)的句柄。
  • 初始化
    為類的靜態(tài)變量賦予正確的初始值
    因?yàn)镴ava中對(duì)類變量進(jìn)行初始值設(shè)定有兩種方式:
    ①聲明類變量是指定初始值
    ②使用靜態(tài)代碼塊為類變量指定初始值
    所以為類的靜態(tài)變量賦予正確的初始值就是執(zhí)行這兩項(xiàng)喉童,他們之間的優(yōu)先級(jí)是一樣的撇寞,如果同時(shí)包含多個(gè)靜態(tài)變量和靜態(tài)代碼塊,則按照自上而下的順序依次執(zhí)行堂氯。
    如果開始初始化一個(gè)類的時(shí)候蔑担,發(fā)現(xiàn)他的父類還沒初始化,那就優(yōu)先初始化其父類咽白。(這時(shí)候判斷父類有沒進(jìn)行了加載钟沛、驗(yàn)證、準(zhǔn)備局扶、解析等,沒有的話就去先做這些然后再對(duì)父類初始化)
    上面提到叁扫,靜態(tài)代碼塊和靜態(tài)變量引用的類也是一樣三妈,這個(gè)時(shí)候被引用的類沒有初始化就去做初始化類的操作(也需要想判斷有沒有加載、驗(yàn)證莫绣、準(zhǔn)備畴蒲、解析等)。

六对室、類用什么加載模燥?

用類加載器加載咖祭,類加載器包含以下幾種:

  • 啟動(dòng)類加載器:Bootstrap ClassLoader,負(fù)責(zé)加載存放在JDK\jre\lib(JDK代表JDK的安裝目錄蔫骂,下同)下么翰,或被-Xbootclasspath參數(shù)指定的路徑中的,并且能被虛擬機(jī)識(shí)別的類庫(kù)(如rt.jar辽旋,所有的java.*開頭的類均被Bootstrap ClassLoader加載)浩嫌。啟動(dòng)類加載器是無(wú)法被Java程序直接引用的。

  • 擴(kuò)展類加載器:Extension ClassLoader补胚,該加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)码耐,它負(fù)責(zé)加載DK\jre\lib\ext目錄中,或者由java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫(kù)(如javax.*開頭的類)溶其,開發(fā)者可以直接使用擴(kuò)展類加載器骚腥。

  • 應(yīng)用程序類加載器:Application ClassLoader,該類加載器由sun.misc.Launcher$AppClassLoader來(lái)實(shí)現(xiàn)瓶逃,它負(fù)責(zé)加載用戶類路徑(ClassPath)所指定的類束铭,開發(fā)者可以直接使用該類加載器,如果應(yīng)用程序中沒有自定義過自己的類加載器金闽,一般情況下這個(gè)就是程序中默認(rèn)的類加載器纯露。

  • 自定義的類加載器

應(yīng)用程序都是由前三種類加載器互相配合進(jìn)行加載的,如果有必要代芜,我們還可以加入自定義的類加載器埠褪。因?yàn)镴VM自帶的ClassLoader只是懂得從本地文件系統(tǒng)加載標(biāo)準(zhǔn)的java class文件,因此如果編寫了自己的ClassLoader挤庇,便可以做到如下幾點(diǎn):
1)在執(zhí)行非置信代碼之前钞速,自動(dòng)驗(yàn)證數(shù)字簽名。
2)動(dòng)態(tài)地創(chuàng)建符合用戶特定需要的定制化構(gòu)建類嫡秕。
3)從特定的場(chǎng)所取得java class渴语,例如數(shù)據(jù)庫(kù)中和網(wǎng)絡(luò)中。

七昆咽、類加載器的加載機(jī)制驾凶?

? 全盤負(fù)責(zé),當(dāng)一個(gè)類加載器負(fù)責(zé)加載某個(gè)Class時(shí)掷酗,該Class所依賴的和引用的其他Class也將由該類加載器負(fù)責(zé)載入调违,除非顯示使用另外一個(gè)類加載器來(lái)載入

? 父類委托,先讓父類加載器試圖加載該類泻轰,只有在父類加載器無(wú)法加載該類時(shí)才嘗試從自己的類路徑中加載該類

? 緩存機(jī)制技肩,緩存機(jī)制將會(huì)保證所有加載過的Class都會(huì)被緩存,當(dāng)程序中需要使用某個(gè)Class時(shí)浮声,類加載器先從緩存區(qū)尋找該Class虚婿,只有緩存區(qū)不存在旋奢,系統(tǒng)才會(huì)讀取該類對(duì)應(yīng)的二進(jìn)制數(shù)據(jù),并將其轉(zhuǎn)換成Class對(duì)象然痊,存入緩存區(qū)至朗。這就是為什么修改了Class后,必須重啟JVM玷过,程序的修改才會(huì)生效

雙親委派模型
雙親委派模型的工作流程是:如果一個(gè)類加載器收到了類加載的請(qǐng)求爽丹,它首先不會(huì)自己去嘗試加載這個(gè)類,而是把請(qǐng)求委托給父加載器去完成辛蚊,依次向上粤蝎,因此,所有的類加載請(qǐng)求最終都應(yīng)該被傳遞到頂層的啟動(dòng)類加載器中袋马,只有當(dāng)父加載器在它的搜索范圍中沒有找到所需的類時(shí)初澎,即無(wú)法完成該加載,子加載器才會(huì)嘗試自己去加載該類虑凛。
雙親委派的例子:
1碑宴、當(dāng)AppClassLoader加載一個(gè)class時(shí),它首先不會(huì)自己去嘗試加載這個(gè)類桑谍,而是把類加載請(qǐng)求委派給父類加載器ExtClassLoader去完成延柠。
2、當(dāng)ExtClassLoader加載一個(gè)class時(shí)锣披,它首先也不會(huì)自己去嘗試加載這個(gè)類贞间,而是把類加載請(qǐng)求委派給BootStrapClassLoader去完成。
3雹仿、如果BootStrapClassLoader加載失斣鋈取(例如在$JAVA_HOME/jre/lib里未查找到該class),會(huì)使用ExtClassLoader來(lái)嘗試加載胧辽;
4峻仇、若ExtClassLoader也加載失敗,則會(huì)使用AppClassLoader來(lái)加載邑商,如果AppClassLoader也加載失敗摄咆,則會(huì)報(bào)出異常ClassNotFoundException。

雙親委派模型意義:

  • 系統(tǒng)類防止內(nèi)存中出現(xiàn)多份同樣的字節(jié)碼
  • 保證Java程序安全穩(wěn)定運(yùn)行人断,不然可能會(huì)出現(xiàn)自己定義一個(gè)Object對(duì)象的情況出現(xiàn)

補(bǔ)充1:類的生命周期是什么豆同?

類的生命周期是加載、驗(yàn)證含鳞、準(zhǔn)備、解析芹务、初始化蝉绷、使用鸭廷、卸載

補(bǔ)充2:類對(duì)象實(shí)例化的初始化順序

實(shí)例化一個(gè)類的時(shí)候,初始化順序是:
父類靜態(tài)代碼塊熔吗、父類靜態(tài)變量(優(yōu)先級(jí)并列) --->
子類靜態(tài)代碼塊辆床、子類靜態(tài)變量 (優(yōu)先級(jí)并列)--->
父類代碼塊 --->
父類構(gòu)造函數(shù) --->
子類代碼塊 --->
子類構(gòu)造函數(shù)

其中父類靜態(tài)代碼塊、父類靜態(tài)變量>子類靜態(tài)代碼塊桅狠、子類靜態(tài)變量這個(gè)是類加載的時(shí)候做的事讼载,所以只在jvm生命周期內(nèi)加載類的時(shí)候做一次,后面實(shí)例化這個(gè)類的對(duì)象就執(zhí)行代碼塊和構(gòu)造函數(shù)的代碼就好了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末中跌,一起剝皮案震驚了整個(gè)濱河市咨堤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌漩符,老刑警劉巖一喘,帶你破解...
    沈念sama閱讀 212,657評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異漱竖,居然都是意外死亡丰歌,警方通過查閱死者的電腦和手機(jī)瞧挤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,662評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)萎战,“玉大人,你說(shuō)我怎么就攤上這事舆逃÷煳” “怎么了?”我有些...
    開封第一講書人閱讀 158,143評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵颖侄,是天一觀的道長(zhǎng)鸟雏。 經(jīng)常有香客問我,道長(zhǎng)览祖,這世上最難降的妖魔是什么孝鹊? 我笑而不...
    開封第一講書人閱讀 56,732評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮展蒂,結(jié)果婚禮上又活,老公的妹妹穿的比我還像新娘。我一直安慰自己锰悼,他們只是感情好柳骄,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,837評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著箕般,像睡著了一般耐薯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,036評(píng)論 1 291
  • 那天曲初,我揣著相機(jī)與錄音体谒,去河邊找鬼。 笑死臼婆,一個(gè)胖子當(dāng)著我的面吹牛抒痒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播颁褂,決...
    沈念sama閱讀 39,126評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼故响,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了颁独?” 一聲冷哼從身側(cè)響起彩届,我...
    開封第一講書人閱讀 37,868評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奖唯,沒想到半個(gè)月后惨缆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,315評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丰捷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,641評(píng)論 2 327
  • 正文 我和宋清朗相戀三年坯墨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片病往。...
    茶點(diǎn)故事閱讀 38,773評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捣染,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出停巷,到底是詐尸還是另有隱情耍攘,我是刑警寧澤,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布畔勤,位于F島的核電站蕾各,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏庆揪。R本人自食惡果不足惜式曲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缸榛。 院中可真熱鬧吝羞,春花似錦、人聲如沸内颗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,859評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)均澳。三九已至恨溜,卻和暖如春符衔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糟袁。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工柏腻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人系吭。 一個(gè)月前我還...
    沈念sama閱讀 46,584評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像颗品,于是被迫代替她去往敵國(guó)和親肯尺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,676評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 聲明:原創(chuàng)文章躯枢,轉(zhuǎn)載請(qǐng)注明出處则吟。http://www.reibang.com/u/e02df63eaa87 1、什...
    唐影若凡閱讀 529評(píng)論 0 4
  • 1锄蹂、什么是類的加載 類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中氓仲,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi)...
    Java_Explorer閱讀 304評(píng)論 0 2
  • 1、什么是類的加載 類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中得糜,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi)...
    小白不想上班閱讀 124評(píng)論 0 0
  • ?1敬扛、什么是類的加載 類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)...
    王知無(wú)閱讀 244評(píng)論 0 2
  • 1朝抖、什么是類的加載機(jī)制 類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中啥箭,將其放在運(yùn)行時(shí)數(shù)據(jù)...
    huststl閱讀 380評(píng)論 0 1