類加載機制

1贸营、類加載的時機

類從被加載到虛擬機內(nèi)存中開始,到卸載出內(nèi)存為止,它的整個生命周期包括:加載(Loading)侍筛、驗證(Verification)、準(zhǔn)備(Preparation)撒穷、解析(Resolution)匣椰、初始化(Initialization)、使用(Using)和卸載(Unloading)端礼。

? ??

2禽笑、有且只有以下五種情況必須立即對類進行(初始化)

①遇到new、getstatic蛤奥、pusstatic或invokestatic這4條字節(jié)碼zhiling時佳镜,如果類沒有進行過初始化,則需要先出發(fā)其初始化凡桥。生成這4條指令的最常見的java代碼場景是:使用new關(guān)鍵字實例化對象的時候蟀伸、讀取或設(shè)置一個類的靜態(tài)字段(被final修飾、已在編譯期把結(jié)果放入常量池的靜態(tài)字段除外)的時候缅刽,以及調(diào)用一個類的靜態(tài)方法的時候啊掏。

②使用java.lang.reflect包的方法對類進行反射調(diào)用的時候,如果類沒有進行過初始化拷恨,則需要先出發(fā)其初始化脖律。

③當(dāng)初始化一個類的時候,如果發(fā)現(xiàn)其父類還沒有進行過初始化腕侄,則需要先觸發(fā)其父類的初始化小泉。

④當(dāng)虛擬機啟動時,用戶需呀執(zhí)行一個要執(zhí)行的主類(包含main()方法的那個類)冕杠,虛擬機會先初始化這個主類微姊。

⑤當(dāng)使用jdk1.7的動態(tài)語言支持時,如果一個java.lang.invoke.MethodHandle實例最后的解析結(jié)果REF_getStatic分预、REF_putStatic兢交、REF_invokeStatic的方法句柄,并且這個方法句柄所對應(yīng)的類沒有進行過初始化笼痹,則需要先觸發(fā)其初始化配喳。

3酪穿、以上5種引用被稱為主動引用,以下是被動引用的例子

? ??

4晴裹、加載被济。虛擬機完成以下三件事

通過一個類的全限定名來獲取定義此類的二進制字節(jié)流

將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)

在內(nèi)存中生成一個代表這個類的java.lang.Class對象,最為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口涧团。

說明:加載二進制字節(jié)流的來源

從zip包中獲取只磷,最終成為日后jar、ear泌绣、war格式的基礎(chǔ)

從網(wǎng)絡(luò)中獲取钮追。典型應(yīng)用applet

運行時計算生成。使用場景動態(tài)代理技術(shù)阿迈,java.lang.reflect.Proxy

由其他文件生成元媚,典型場景是jsp應(yīng)用,即由jsp文件生成對應(yīng)的class類

從數(shù)據(jù)庫中讀取苗沧,中間件服務(wù)器

數(shù)組類加載說明:數(shù)組類本身不通過類加載器創(chuàng)建惠毁,她由java虛擬機直接創(chuàng)建的。單數(shù)組類與類加載器仍然有很密切的關(guān)系崎页,因為數(shù)組類的元素類型(elementType,指的是數(shù)組去掉所有維度的類型)最終是要靠類加載器去創(chuàng)建腰埂,一個數(shù)組類飒焦。

5、驗證:是連接階段的第一步屿笼,這一階段的目的是為了確保class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機的要求牺荠,并且不會危害虛擬機自身的安全。

文件格式驗證:字節(jié)流是否符合Class文件格式的規(guī)范

元數(shù)據(jù)驗證:對字節(jié)碼描述的信息進行語義分析

字節(jié)碼驗證:通過數(shù)據(jù)流和控制流分析驴一,確定程序語義是合法的休雌、符合邏輯的

符號引用驗證:虛擬機將符號轉(zhuǎn)化為直接引用的時候

6、準(zhǔn)備:正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段肝断,這些變量所使用的內(nèi)存都將在方法區(qū)中進行分配杈曲。這個階段進行內(nèi)存分配的僅包括類變量(被static修飾的變量),而不包括實例變量胸懈,實例變量將會在對象實例化時隨著對象一起分配在java堆中担扑。其次,這里所說的初始值“通常情況”下是數(shù)據(jù)類型的零值趣钱。public static int value=123涌献;準(zhǔn)備階段是0,程序被編譯后value=123首有⊙嗬“特殊情況”

:如果類字段的字段屬性變種ConstangVaule屬性枢劝,那在準(zhǔn)備階段變量value就會被初始化為ConstangValue屬性所指定的值。

7卜壕、解析:虛擬機將常量池內(nèi)的符號引用替換為直接引用的過程您旁。

????????類或接口的解析

????????字段解析

????????類方法解析

????????接口方法解析

8、初始化:執(zhí)行類構(gòu)造器方法的過程

① ????<clinit>()方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態(tài)語句塊(static{}塊)中的語句合并產(chǎn)生的印叁,編譯器收集的順序是由語句在源文件中出現(xiàn)的順序所決定的被冒,靜態(tài)語句塊中只能訪問到定義在靜態(tài)語句塊之前的變量,定義在它之后的變量轮蜕,在前面的靜態(tài)語句塊可以賦值昨悼,但是不能訪問

②????<clinit>()方法與類的構(gòu)造函數(shù)不同,她不需要顯示地調(diào)用父類構(gòu)造器跃洛,虛擬機會保證在子類的<clinit>()方法執(zhí)行之前率触,父類的<clinit>()方法已經(jīng)執(zhí)行完畢。

③????由于父類的<clinit>()方法先執(zhí)行汇竭,也就意味著父類中定義的靜態(tài)語句塊要優(yōu)先于子類的變量賦值操作葱蝗。

? ??

④????<clinit>()方法對與類或接口來說并不是必須的,如果一個類中沒有靜態(tài)語句塊细燎,也沒有對變量的賦值操作两曼,那么編譯器可以不為這個類生成<clinit>()方法。

⑤????接口中不能使用靜態(tài)語句塊玻驻,單任然有變量初始化的賦值操作悼凑,因此接口與類一樣都會生成<clinit>()方法。但接口與類不同的是璧瞬,執(zhí)行接口的<clinit>()方法不需要先執(zhí)行父接口的<clinit>()方法户辫。只有單父接口中定義的變量使用時,符接口才會初始化嗤锉。另外渔欢,接口的實現(xiàn)類在初始化時也一樣不會執(zhí)行接口的<clinit>()方法。

⑥????虛擬機會保證一個類的<clinit>()方法在多線程環(huán)境中被正確地加鎖瘟忱、同步奥额,如果多個線程同時去初始化一個類,那么只會有一個線程去執(zhí)行這個類的<clinit>()方法酷誓,其他線程都需要阻塞等待披坏,知道活動線程執(zhí)行<clinit>()方法完畢。如果一個類的<clinit>()方法中有耗時很長的操作盐数,就可能造成多個進程阻塞棒拂,在實際應(yīng)用中這種阻塞往往是很隱蔽的。

9、類加載器

① 類與類加載器

類加載器雖然只用于顯示類的加載動作帚屉,但它在java程序中起到的作用卻遠(yuǎn)遠(yuǎn)不限于類加載階段谜诫。對于任意一個類,都需要由加載它的類加載器和這個類本身一同確立其在java虛擬機中的唯一性攻旦,每一個類加載器喻旷,都擁有一個獨立的類名稱空間,即比較兩個類是否相等牢屋,只有在這兩個類是由同一個類加載器加載的前提下才有意義且预,否則,及時這兩個類來源同一個Class文件烙无,唄同一個虛擬機加載锋谐,只要加載他們的類加載器不同,那這兩個類必定不相等截酷。

以上為false的結(jié)果涮拗,因為虛擬機中存在勒兩個ClassLoaderTest類,一個是由系統(tǒng)應(yīng)用程序類加載器加載的迂苛,另一個是由我們自定義的類加載器加載的三热,雖然都來自同一個Class文件,但依然是兩個獨立的類三幻,做對象所屬類型檢查是結(jié)果自然為false就漾。

② 雙親委派模型

從java虛擬機的角度來講,只存在兩種不同的類加載器:一種是啟動類加載器(bootstrap classloader)念搬,這個類加載器使用C++語言實現(xiàn)从藤,是虛擬機自身的一部分;另一種就是所有其他的類加載器锁蠕,這些類加載器都由java語言實現(xiàn),獨立于虛擬機外部懊蒸,并且圈都繼承自抽象類java.lang.ClassLoader荣倾。

????????①啟動類加載器(Bootstrap ClassLoader):負(fù)責(zé)將存放在\lib目錄中的,或者被-Xbootclasspath參數(shù)鎖指定的路徑中的骑丸,并且是虛擬機是被的類庫加載到虛擬機內(nèi)存中舌仍。啟動類加載器無法被java程序直接引用,用戶在編寫自定義類加載器時通危,如果需要把加載請求委派給引導(dǎo)類加載器铸豁,那直接使用null代替即可

????????②擴展類加載器(Extension ClassLoader):這個加載器由sun.misc.Launcher$ExtClassLoader實現(xiàn),它負(fù)責(zé)\lib\ext目錄中的菊碟,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫节芥,開發(fā)者可以直接使用擴展類加載器。

????????③應(yīng)用程序類加載器(Application ClassLoader):這個類加載器由sun.misc.Launcher$AppClassLoader實現(xiàn)。由于這個類加載器時ClassLoader中的getSystemClassLoader()方法的返回值头镊,所以一邊稱他為系統(tǒng)類加載器蚣驼。它負(fù)責(zé)加載用戶類路徑(ClassPath)上所指定的類庫,開發(fā)者可以直接使用這個類加載器相艇,如果應(yīng)用程序中國沒有自定義過自己的類加載器颖杏,一邊情況下這個就是程序中默認(rèn)的類加載器。

雙親委派模型(Parents Delegation Model):要求除了頂層的啟動類加載器外坛芽,其余的類加載器都硬蛋有自己的父類加載器留储。這里類加載器之間的負(fù)責(zé)關(guān)系一邊不會一繼承的管事來實現(xiàn),而是都使用組合關(guān)系來復(fù)用父加載器的代碼咙轩。

雙親委派模型的工作過程:如果一個類加載器收到了類加載的請求获讳,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成臭墨,每一個層次的類加載器都是如此赔嚎,因此所有的加載請求最終都應(yīng)該傳送到頂層的啟動類加載器中,只有當(dāng)附加在前反饋自己無法完成這個加載請求時胧弛,自加載器才會嘗試自己去加載尤误。

破壞雙親委派模型

????????①jdk1.2上線后為了保證類加載機制復(fù)合雙親模式,并兼容之前的代碼在ClassLoader中新加了一個findClass()方法结缚。

????????②基礎(chǔ)類調(diào)用用戶的代碼损晤。如JNDI(需要調(diào)用獨立廠商實現(xiàn)并部署的應(yīng)用程序的ClassPath下的jndi接口提供者SPI,service provider interface)红竭,但啟動類加載器不可能認(rèn)識這些代碼尤勋,java開發(fā)團隊引入線程上下文類加載器(Thread Context ClassLoader)。java中所有涉及spi的加載動作基本上都采用這種方式茵宪。如JNDI,JDBC,JAXB,JBI

????????③用戶對程序動態(tài)性的追求導(dǎo)致的最冰。代碼如替換、模塊熱部署稀火。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末暖哨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子凰狞,更是在濱河造成了極大的恐慌篇裁,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赡若,死亡現(xiàn)場離奇詭異达布,居然都是意外死亡,警方通過查閱死者的電腦和手機逾冬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門黍聂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事分冈』恚” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵雕沉,是天一觀的道長集乔。 經(jīng)常有香客問我,道長坡椒,這世上最難降的妖魔是什么扰路? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮倔叼,結(jié)果婚禮上汗唱,老公的妹妹穿的比我還像新娘。我一直安慰自己丈攒,他們只是感情好哩罪,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著巡验,像睡著了一般际插。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上显设,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天框弛,我揣著相機與錄音,去河邊找鬼捕捂。 笑死瑟枫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的指攒。 我是一名探鬼主播慷妙,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼允悦!你這毒婦竟也來了景殷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤澡屡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咐旧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驶鹉,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年铣墨,在試婚紗的時候發(fā)現(xiàn)自己被綠了室埋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖姚淆,靈堂內(nèi)的尸體忽然破棺而出孕蝉,到底是詐尸還是另有隱情,我是刑警寧澤腌逢,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布降淮,位于F島的核電站,受9級特大地震影響搏讶,放射性物質(zhì)發(fā)生泄漏佳鳖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一媒惕、第九天 我趴在偏房一處隱蔽的房頂上張望系吩。 院中可真熱鬧,春花似錦妒蔚、人聲如沸穿挨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽科盛。三九已至,卻和暖如春叁鉴,著一層夾襖步出監(jiān)牢的瞬間土涝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工幌墓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留但壮,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓常侣,卻偏偏與公主長得像蜡饵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子胳施,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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

  • 代碼編譯的結(jié)果從本地機器碼轉(zhuǎn)變?yōu)樽止?jié)碼溯祸,是存儲格式發(fā)展的一小步,確實編譯語言發(fā)展的一大步舞肆。 虛擬機把描述類的數(shù)據(jù)從...
    胡二囧閱讀 954評論 0 0
  • C/C++在運行前需要完成預(yù)處理焦辅、編譯、匯編椿胯、鏈接筷登;而在Java中,類加載(加載哩盲、連接前方、初始化)是在程序運行期間第...
    Steven1997閱讀 964評論 1 2
  • 原文鏈接:Java 類加載機制(阿里面試題)-何時初始化類 - aspirant - 博客園 閱讀目錄 什么是類加...
    Walter_Hu閱讀 924評論 0 8
  • 每一個物業(yè)人員剛剛進入物業(yè)行業(yè)的時候狈醉,全都是雄心萬丈,一心想有一番作為惠险,并且他們也為他們的夢想付出努力了苗傅。...
    丿火花灬閱讀 1,136評論 0 1
  • Nginx 的大名從我接觸開發(fā)以來如雷貫耳,但一直不清楚具體用法,今天就來研究一下.... 安裝 安裝后目錄在/u...
    blossom_綻放閱讀 161評論 0 0