fegin需要实现类_深入理解JVM(六)--虚拟机类加载机制
虛擬機(jī)把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直接使用的Java類型,這就是虛擬機(jī)的類加載機(jī)制。
類從被加載到虛擬機(jī)內(nèi)存開(kāi)始,到卸載出內(nèi)存為止,它的整個(gè)生命周期包括:加載、驗(yàn)證、準(zhǔn)備、解析、初始化、使用和卸載七個(gè)階段。
類的生命周期1.加載
"加載"是"類加載"這個(gè)過(guò)程的一個(gè)階段,是 “類加載”過(guò)程中最先開(kāi)始進(jìn)行的操作,加載階段,虛擬機(jī)需要完成三件事:
2.驗(yàn)證
驗(yàn)證是連接的第一步,這一階段的目的是為了確保Class文件的字節(jié)流包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害到虛擬機(jī)自身的安全。虛擬機(jī)如果不檢查輸入的字節(jié)流,對(duì)其完全信任的話,很可能會(huì)因?yàn)檩d入了有害字節(jié)流而導(dǎo)致系統(tǒng)崩潰。
(1)文件格式驗(yàn)證
檢查字節(jié)流是否符合Class文件格式的規(guī)范,并且能被當(dāng)前版本的虛擬機(jī)處理:
- 是否以魔數(shù)0XCAFEBABE開(kāi)頭。
- 主、次版本號(hào)是否存在當(dāng)前虛擬機(jī)處理范圍內(nèi)。
- 常量池的常量是否有不被支持的常量類型。
- ... ...
(2)元數(shù)據(jù)驗(yàn)證
對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析,以保證其描述的信息符合Java語(yǔ)言規(guī)范的要求:
- 這個(gè)類是否有父類。
- 這個(gè)類的父類是否繼承了不允許繼承的類。
- 如果這個(gè)類不是抽象類,是否實(shí)現(xiàn)了其父類或接口之中要求實(shí)現(xiàn)的所有方法。
- ... ...
(3)字節(jié)碼驗(yàn)證
(4)符號(hào)引用驗(yàn)證
3.準(zhǔn)備
準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。
4.解析
解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程。
5.初始化
前面的類加載過(guò)程中,除了在加載階段用戶應(yīng)用程序可以通過(guò)自定義類加載器參與之外,其余動(dòng)作完全由虛擬機(jī)主導(dǎo)和控制。到了初始化階段,才真正開(kāi)始執(zhí)行類中定義的Java程序代碼。
虛擬機(jī)規(guī)范嚴(yán)格規(guī)定了有且只有5種情況必須立即對(duì)類進(jìn)行“初始化”:
(1)遇到new、getstatic、putstatic或invokestatic這4條字節(jié)碼指令時(shí),如果類沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其初始化。生成這4條指令的最常見(jiàn)的Java代碼場(chǎng)景是:使用new關(guān)鍵字實(shí)例化對(duì)象的時(shí)候、讀取或設(shè)置一個(gè)類的靜態(tài)字段的時(shí)候、調(diào)用一個(gè)類的靜態(tài)方法的時(shí)候。
(2)使用java.lang.reflect包的方法對(duì)類進(jìn)行反射調(diào)用的時(shí)候,如果類沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其初始化。
(3)當(dāng)初始化一個(gè)類的時(shí)候,如果發(fā)現(xiàn)其父類還沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其父類初始化。
(4)當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要指定一個(gè)要執(zhí)行的主類(包含main()方法的類),虛擬機(jī)會(huì)先初始化這個(gè)主類。
(5)當(dāng)使用JDK1.7的動(dòng)態(tài)語(yǔ)言支持時(shí),如果一個(gè)java.lang.invoke.MethodHandle實(shí)例最后的解析結(jié)果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且這個(gè)方法句柄所對(duì)應(yīng)的類沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)初始化。
6.類加載器雙親委派模型
從Java虛擬機(jī)的角度來(lái)說(shuō),只存在兩種不同的類加載器:一種是啟動(dòng)類加載器(Bootstrap ClassLoader),這個(gè)類加載器使用C++語(yǔ)言實(shí)現(xiàn)(HotSpot虛擬機(jī)中),是虛擬機(jī)自身的一部分;另一種就是所有其他的類加載器,這些類加載器都有Java語(yǔ)言實(shí)現(xiàn),獨(dú)立于虛擬機(jī)外部,并且全部繼承自java.lang.ClassLoader。
從開(kāi)發(fā)者的角度,類加載器可以細(xì)分為:
啟動(dòng)類加載器:負(fù)責(zé)將 Java_Home/lib下面的類庫(kù)加載到內(nèi)存中(比如rt.jar)。由于引導(dǎo)類加載器涉及到虛擬機(jī)本地實(shí)現(xiàn)細(xì)節(jié),開(kāi)發(fā)者無(wú)法直接獲取到啟動(dòng)類加載器的引用,所以不允許直接通過(guò)引用進(jìn)行操作。
擴(kuò)展類加載器:由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)。它負(fù)責(zé)將Java_Home /lib/ext或者由系統(tǒng)變量 java.ext.dir指定位置中的類庫(kù)加載到內(nèi)存中。開(kāi)發(fā)者可以直接使用標(biāo)準(zhǔn)擴(kuò)展類加載器。
應(yīng)用程序類加載器:由 sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)的。它負(fù)責(zé)將系統(tǒng)類路徑(CLASSPATH)中指定的類庫(kù)加載到內(nèi)存中。開(kāi)發(fā)者可以直接使用這個(gè)類加載器。
除此之外,還有自定義的類加載器,它們之間的層次關(guān)系被稱為類加載器的雙親委派模型。該模型要求除了頂層的啟動(dòng)類加載器外,其余的類加載器都應(yīng)該有自己的父類加載器,而這種父子關(guān)系一般通過(guò)組合(Composition)關(guān)系來(lái)實(shí)現(xiàn),而不是通過(guò)繼承(Inheritance)。
類加載器雙親委派模型雙親委派模型的工作原理是,如果一個(gè)類加載器收到了類加載請(qǐng)求,它首先不會(huì)自己去嘗試加載這個(gè)類,而是把這個(gè)請(qǐng)求委派給父類加載器去執(zhí)行,每一個(gè)層次的類加載器都是如此,因此所有的加載請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類加載器中,只有當(dāng)父類加載器反饋?zhàn)约簾o(wú)法完成這個(gè)加載請(qǐng)求時(shí),子加載器才會(huì)嘗試自己去加載。
優(yōu)勢(shì):(1)采用雙親委派模式的是好處是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系,通過(guò)這種層級(jí)關(guān)可以避免類的重復(fù)加載,當(dāng)父親已經(jīng)加載了該類時(shí),就沒(méi)有必要子ClassLoader再加載一次。(2)實(shí)現(xiàn)簡(jiǎn)單,邏輯清晰易懂。
總結(jié)
以上是生活随笔為你收集整理的fegin需要实现类_深入理解JVM(六)--虚拟机类加载机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: css初始化样式文件_前端必备技能 we
- 下一篇: 怎么复制黑苹果config配置_估计是最