- Offer來了:Java面試核心知識(shí)點(diǎn)精講(原理篇)
- 王磊
- 2074字
- 2020-04-03 12:50:09
1.10 JVM的類加載機(jī)制
1.10.1 JVM的類加載階段
JVM的類加載分為5個(gè)階段:加載、驗(yàn)證、準(zhǔn)備、解析、初始化。在類初始化完成后就可以使用該類的信息,在一個(gè)類不再被需要時(shí)可以從JVM中卸載,如圖1-20所示。

圖1-20
1.加載
指JVM讀取Class文件,并且根據(jù)Class文件描述創(chuàng)建java.lang.Class對(duì)象的過程。類加載過程主要包含將Class文件讀取到運(yùn)行時(shí)區(qū)域的方法區(qū)內(nèi),在堆中創(chuàng)建java.lang.Class對(duì)象,并封裝類在方法區(qū)的數(shù)據(jù)結(jié)構(gòu)的過程,在讀取Class文件時(shí)既可以通過文件的形式讀取,也可以通過jar包、war包讀取,還可以通過代理自動(dòng)生成Class或其他方式讀取。
2.驗(yàn)證
主要用于確保Class文件符合當(dāng)前虛擬機(jī)的要求,保障虛擬機(jī)自身的安全,只有通過驗(yàn)證的Class文件才能被JVM加載。
3.準(zhǔn)備
主要工作是在方法區(qū)中為類變量分配內(nèi)存空間并設(shè)置類中變量的初始值。初始值指不同數(shù)據(jù)類型的默認(rèn)值,這里需要注意final類型的變量和非final類型的變量在準(zhǔn)備階段的數(shù)據(jù)初始化過程不同。比如一個(gè)成員變量的定義如下:
public static long value = 1000;
在以上代碼中,靜態(tài)變量value在準(zhǔn)備階段的初始值是0,將value設(shè)置為1000的動(dòng)作是在對(duì)象初始化時(shí)完成的,因?yàn)镴VM在編譯階段會(huì)將靜態(tài)變量的初始化操作定義在構(gòu)造器中。但是,如果將變量value聲明為final類型:
public static final int value = 1000;
則JVM在編譯階段后會(huì)為final類型的變量value生成其對(duì)應(yīng)的ConstantValue屬性,虛擬機(jī)在準(zhǔn)備階段會(huì)根據(jù)ConstantValue屬性將value賦值為1000。
4.解析
JVM會(huì)將常量池中的符號(hào)引用替換為直接引用。
5.初始化
主要通過執(zhí)行類構(gòu)造器的<client>方法為類進(jìn)行初始化。<client>方法是在編譯階段由編譯器自動(dòng)收集類中靜態(tài)語句塊和變量的賦值操作組成的。JVM規(guī)定,只有在父類的<client>方法都執(zhí)行成功后,子類中的<client>方法才可以被執(zhí)行。在一個(gè)類中既沒有靜態(tài)變量賦值操作也沒有靜態(tài)語句塊時(shí),編譯器不會(huì)為該類生成<client>方法。
在發(fā)生以下幾種情況時(shí),JVM不會(huì)執(zhí)行類的初始化流程。
◎ 常量在編譯時(shí)會(huì)將其常量值存入使用該常量的類的常量池中,該過程不需要調(diào)用常量所在的類,因此不會(huì)觸發(fā)該常量類的初始化。
◎ 在子類引用父類的靜態(tài)字段時(shí),不會(huì)觸發(fā)子類的初始化,只會(huì)觸發(fā)父類的初始化。
◎ 定義對(duì)象數(shù)組,不會(huì)觸發(fā)該類的初始化。
◎ 在使用類名獲取Class對(duì)象時(shí)不會(huì)觸發(fā)類的初始化。
◎ 在使用Class.forName加載指定的類時(shí),可以通過initialize參數(shù)設(shè)置是否需要對(duì)類進(jìn)行初始化。
◎ 在使用ClassLoader默認(rèn)的loadClass方法加載類時(shí)不會(huì)觸發(fā)該類的初始化。
1.10.2 類加載器
JVM提供了3種類加載器,分別是啟動(dòng)類加載器、擴(kuò)展類加載器和應(yīng)用程序類加載器,如圖1-21所示。

圖1-21
(1)啟動(dòng)類加載器:負(fù)責(zé)加載Java_HOME/lib目錄中的類庫,或通過-Xbootclasspath參數(shù)指定路徑中被虛擬機(jī)認(rèn)可的類庫。
(2)擴(kuò)展類加載器:負(fù)責(zé)加載Java_HOME/lib/ext目錄中的類庫,或通過java.ext.dirs系統(tǒng)變量加載指定路徑中的類庫。
(3)應(yīng)用程序類加載器:負(fù)責(zé)加載用戶路徑(classpath)上的類庫。
除了上述3種類加載器,我們也可以通過繼承java.lang.ClassLoader實(shí)現(xiàn)自定義的類加載器。
1.10.3 雙親委派機(jī)制
JVM通過雙親委派機(jī)制對(duì)類進(jìn)行加載。雙親委派機(jī)制指一個(gè)類在收到類加載請(qǐng)求后不會(huì)嘗試自己加載這個(gè)類,而是把該類加載請(qǐng)求向上委派給其父類去完成,其父類在接收到該類加載請(qǐng)求后又會(huì)將其委派給自己的父類,以此類推,這樣所有的類加載請(qǐng)求都被向上委派到啟動(dòng)類加載器中。若父類加載器在接收到類加載請(qǐng)求后發(fā)現(xiàn)自己也無法加載該類(通常原因是該類的Class文件在父類的類加載路徑中不存在),則父類會(huì)將該信息反饋給子類并向下委派子類加載器加載該類,直到該類被成功加載,若找不到該類,則JVM會(huì)拋出ClassNotFoud異常。
雙親委派類加載機(jī)制的類加載流程如下,如圖1-22所示。

圖1-22
(1)將自定義加載器掛載到應(yīng)用程序類加載器。
(2)應(yīng)用程序類加載器將類加載請(qǐng)求委托給擴(kuò)展類加載器。
(3)擴(kuò)展類加載器將類加載請(qǐng)求委托給啟動(dòng)類加載器。
(4)啟動(dòng)類加載器在加載路徑下查找并加載Class文件,如果未找到目標(biāo)Class文件,則交由擴(kuò)展類加載器加載。
(5)擴(kuò)展類加載器在加載路徑下查找并加載Class文件,如果未找到目標(biāo)Class文件,則交由應(yīng)用程序類加載器加載。
(6)應(yīng)用程序類加載器在加載路徑下查找并加載Class文件,如果未找到目標(biāo)Class文件,則交由自定義加載器加載。
(7)在自定義加載器下查找并加載用戶指定目錄下的Class文件,如果在自定義加載路徑下未找到目標(biāo)Class文件,則拋出ClassNotFoud異常。
雙親委派機(jī)制的核心是保障類的唯一性和安全性。例如在加載rt.jar包中的java.lang.Object類時(shí),無論是哪個(gè)類加載器加載這個(gè)類,最終都將類加載請(qǐng)求委托給啟動(dòng)類加載器加載,這樣就保證了類加載的唯一性。如果在JVM中存在包名和類名相同的兩個(gè)類,則該類將無法被加載,JVM也無法完成類加載流程。
1.10.4 OSGI
OSGI(Open Service Gateway Initiative)是Java動(dòng)態(tài)化模塊化系統(tǒng)的一系列規(guī)范,旨在為實(shí)現(xiàn)Java程序的模塊化編程提供基礎(chǔ)條件。基于OSGI的程序可以實(shí)現(xiàn)模塊級(jí)的熱插拔功能,在程序升級(jí)更新時(shí),可以只針對(duì)需要更新的程序進(jìn)行停用和重新安裝,極大提高了系統(tǒng)升級(jí)的安全性和便捷性。
OSGI提供了一種面向服務(wù)的架構(gòu),該架構(gòu)為組件提供了動(dòng)態(tài)發(fā)現(xiàn)其他組件的功能,這樣無論是加入組件還是卸載組件,都能被系統(tǒng)的其他組件感知,以便各個(gè)組件之間能更好地協(xié)調(diào)工作。
OSGI不但定義了模塊化開發(fā)的規(guī)范,還定義了實(shí)現(xiàn)這些規(guī)范所依賴的服務(wù)與架構(gòu),市場(chǎng)上也有成熟的框架對(duì)其進(jìn)行實(shí)現(xiàn)和應(yīng)用,但只有部分應(yīng)用適合采用OSGI方式,因?yàn)樗鼮榱藢?shí)現(xiàn)動(dòng)態(tài)模塊,不再遵循JVM類加載雙親委派機(jī)制和其他JVM規(guī)范,在安全性上有所犧牲。
- JSP網(wǎng)絡(luò)編程(學(xué)習(xí)筆記)
- Python 3.7網(wǎng)絡(luò)爬蟲快速入門
- 薛定宇教授大講堂(卷Ⅳ):MATLAB最優(yōu)化計(jì)算
- 游戲程序設(shè)計(jì)教程
- QTP自動(dòng)化測(cè)試進(jìn)階
- FFmpeg入門詳解:音視頻原理及應(yīng)用
- 后臺(tái)開發(fā):核心技術(shù)與應(yīng)用實(shí)踐
- SSH框架企業(yè)級(jí)應(yīng)用實(shí)戰(zhàn)
- SQL Server實(shí)例教程(2008版)
- 軟硬件綜合系統(tǒng)軟件需求建模及可靠性綜合試驗(yàn)、分析、評(píng)價(jià)技術(shù)
- 軟件開發(fā)中的決策:權(quán)衡與取舍
- Azure for Architects
- Python GUI設(shè)計(jì)tkinter菜鳥編程(增強(qiáng)版)
- Java編程動(dòng)手學(xué)
- Visual FoxPro程序設(shè)計(jì)