類加載機(jī)制(二)遣钳、類加載的過程

上篇文章提到過,類加載一共七步驟:加載麦乞、驗(yàn)證蕴茴、準(zhǔn)備、解析姐直、初始化倦淀、使用、卸載∩罚現(xiàn)在講解前五步驟撞叽。

一姻成、加載
在類加載階段,虛擬機(jī)需要完成以下三件事:
1)通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流
2)將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
3)在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對象,作為方法區(qū)對這個(gè)類的各種數(shù)據(jù)的訪問入口

總結(jié):查找并加載二進(jìn)制字節(jié)碼到方法區(qū)愿棋,然后在內(nèi)存中實(shí)例化一個(gè)java.lang.Class類的對象

二科展、驗(yàn)證
1、文件格式驗(yàn)證

1)是否以魔數(shù)0xCAFEBABE開頭
2)主次版本號是否在當(dāng)前虛擬機(jī)處理范圍之內(nèi)
3)常量池的常量中是否有不被支持的常量類型
4)是否有指向不存在的常量或不符合類型的常量
5)CONSTANT_Utf8_info型的長兩種是否有不符合UTF8編碼的數(shù)據(jù)
6)Class文件中各個(gè)部分及文件本身是否又被刪除的或附加的其他信息
...

該階段的主要目的是保證輸入的字節(jié)流能正確的解析并存儲(chǔ)于方法區(qū)之內(nèi)

2糠雨、元數(shù)據(jù)驗(yàn)證

1)這個(gè)類是否有父類(除了java.lang.Object之外才睹,其他所有的類都應(yīng)該有父類)
2)這個(gè)類的父類是否繼承了不允許被繼承的類(被final修飾的類)
3)如果這個(gè)類不是抽象類,是否實(shí)現(xiàn)了其父類或接口之中要求實(shí)現(xiàn)的所有方法
4)類的字段甘邀,方法是否與父類產(chǎn)生矛盾(例如覆蓋了父類的final字段琅攘,或者出現(xiàn)不符合規(guī)則的方法重載,比如方法參數(shù)都一樣鹃答,但返回值卻不同乎澄。)
...

該階段主要目的是對類的元數(shù)據(jù)信息進(jìn)行語義校驗(yàn),保證不存在不符合Java語言規(guī)范的元數(shù)據(jù)信息测摔。

3置济、字節(jié)碼驗(yàn)證

1)保證任意時(shí)刻操作數(shù)棧的數(shù)據(jù)類型與指令代碼序列都能配合工作,例如不會(huì)出現(xiàn):在操作棧放置了一個(gè)int類型的數(shù)據(jù)锋八,使用時(shí)卻按long類型來加載入本地變量表中
2)保證跳轉(zhuǎn)指令不會(huì)跳轉(zhuǎn)到方法體以外的字節(jié)碼指令上
...

該階段主要目的是通過數(shù)據(jù)流和控制流分析浙于,確定程序語義是合法的、符合邏輯的挟纱。

4羞酗、符號引用驗(yàn)證

1)符號引用中通過字符串描述的全限定名是否能找到對應(yīng)的類
2)在指定類中是否存在符合方法的字段描述符以及簡單名稱所描述的方法和字段
3)符號引用中的類、字段紊服、方法的訪問性是否可以被當(dāng)前類訪問
...

該階段的目的是確保解析動(dòng)作能正常執(zhí)行檀轨,否則將會(huì)拋出一個(gè)java.lang.IncompatibleClasschangeError異常的子類

驗(yàn)證階段是非常重要的,但不是必須的欺嗤,它對程序運(yùn)行期沒有影響参萄,如果所引用的類經(jīng)過反復(fù)驗(yàn)證,那么可以考慮采用-Xverifynone參數(shù)來關(guān)閉大部分的類驗(yàn)證措施煎饼,以縮短虛擬機(jī)類加載的時(shí)間讹挎。

三、準(zhǔn)備
準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段吆玖,這些內(nèi)存都將在方法區(qū)中分配筒溃。

1)這時(shí)候進(jìn)行內(nèi)存分配的僅包括類變量(static),而不包括實(shí)例變量沾乘,實(shí)例變量會(huì)在對象實(shí)例化時(shí)隨著對象一塊分配在Java堆中怜奖。

2)這里所設(shè)置的初始值通常情況下是數(shù)據(jù)類型默認(rèn)的零值(如0、0L翅阵、null烦周、false等)尽爆,而不是被在Java代碼中被顯示的賦予的值。
假設(shè)一個(gè)類變量的定義為:
public static int value = 3;
那么變量value在準(zhǔn)備階段過后的初始值為0读慎,而不是3漱贱,因?yàn)檫@時(shí)候尚未開始執(zhí)行任何Java方法,而把value賦值為3的putstatic指令是在程序編譯后夭委,存放于類構(gòu)造器<clinit>()方法之中的幅狮,所以把value賦值為3的動(dòng)作將在初始化階段才會(huì)執(zhí)行。

3)如果類字段的字段屬性表中存在ConstantValue屬性株灸,即同時(shí)被static 和 final修飾崇摄,那么在準(zhǔn)備階段變量value就會(huì)會(huì)初始化為ConstantValue屬性所指定的值。
假設(shè)上面的變量value被定為:
public static final int value = 3;
編譯時(shí)Javac將會(huì)為value生成ConstantValue屬性慌烧,在準(zhǔn)備階段虛擬機(jī)就會(huì)根據(jù)ConstantValue的設(shè)置將value賦值為3逐抑。

總結(jié):為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值

四屹蚊、解析
解析階段是虛擬機(jī)將常量池內(nèi)的符號引用替換為直接引用的過程厕氨,解析動(dòng)作主要針對類或接口、字段汹粤、類方法命斧、接口方法、方法類型嘱兼、方法句柄和調(diào)用點(diǎn)限定符7類符號引用進(jìn)行国葬。符號引用就是一組符號來描述目標(biāo),可以是任何字面量芹壕。

直接引用就是直接指向目標(biāo)的指針汇四、相對偏移量或一個(gè)間接定位到目標(biāo)的句柄。

總結(jié):把類中的符號引用轉(zhuǎn)換為直接引用

五踢涌、初始化
初始化通孽,為類的靜態(tài)變量賦予正確的初始值,JVM負(fù)責(zé)對類進(jìn)行初始化斯嚎,主要對類變量進(jìn)行初始化。在Java中對類變量進(jìn)行初始值設(shè)定有兩種方式:
①聲明類變量是指定初始值
②使用靜態(tài)代碼塊為類變量指定初始值

初始化也是執(zhí)行類構(gòu)造器<clinit>()方法的過程堡僻。

1)<clinit>()方法是由編譯器自動(dòng)收集類種所有變量的賦值動(dòng)作和靜態(tài)語句塊(static{}塊)中的語句合并產(chǎn)生的,編譯器收集的順序是由語句在源文件中出現(xiàn)的順序所決定的疫剃,靜態(tài)語句塊中只能訪問到定義在靜態(tài)語句塊之前的變量,定義在他之后的變量巢价,在前面的靜態(tài)語句塊可以賦值牲阁,但是不能訪問固阁,如下:

package com.designmodel.javap;

/**
 * 測試
 * 
 * @author 15620646321@163.com
 * @date 2017年5月9日
 */
public class TestCLInit {
    
    static {
        i = 0;
        //Cannot reference a field before it is defined
//      System.out.println(i);
    }
    
    static int i = 1;
}

2)<clinit>()方法與類的構(gòu)造函數(shù)不同,他不需要顯示的調(diào)用父類構(gòu)造器城菊,虛擬機(jī)會(huì)保證在子類的<clinit>()方法執(zhí)行之前备燃,父類的<clinit>()方法已經(jīng)執(zhí)行完畢,因此在虛擬機(jī)中第一個(gè)被執(zhí)行的<clinit>()方法的類肯定是java.lang.Object凌唬。

3)由于父類的<clinit>()方法優(yōu)先執(zhí)行并齐,也就意味著父類中定義的靜態(tài)語句塊要優(yōu)先于子類的變量賦值操作,如下

package com.designmodel.javap;

/**
 * 測試
 * 
 * @author 15620646321@163.com
 * @date 2017年5月9日
 */
public class TestCLInit2 {
    
    static class Parent {
        public static int A = 1;
        
        static {
            A = 2;
        }
    }
    
    static class Sub extends Parent {
        public static int B = A;
    }
    
    public static void main(String[] args) {
        System.out.print(Sub.B);
    }
}

輸出結(jié)果:

2
package com.designmodel.javap;

/**
 * 測試
 * 
 * @author 15620646321@163.com
 * @date 2017年5月9日
 */
public class TestCLInit2 {
    
    static class Parent {
        
        static {
            A = 2;
        }
        public static int A = 1;
    }
    
    static class Sub extends Parent {
        public static int B = A;
    }
    
    public static void main(String[] args) {
        System.out.print(Sub.B);
    }
}

輸出結(jié)果:

1

從結(jié)果發(fā)現(xiàn)客税,編譯器收集的順序是由語句在源文件中出現(xiàn)的順序所決定的况褪。

若有興趣,歡迎來加入群更耻,【Java初學(xué)者學(xué)習(xí)交流群】:458430385测垛,此群有Java開發(fā)人員、UI設(shè)計(jì)人員和前端工程師秧均。有問必答食侮,共同探討學(xué)習(xí),一起進(jìn)步熬北!
歡迎關(guān)注我的微信公眾號【Java碼農(nóng)社區(qū)】疙描,會(huì)定時(shí)推送各種干貨:


qrcode_for_gh_577b64e73701_258.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市讶隐,隨后出現(xiàn)的幾起案子起胰,更是在濱河造成了極大的恐慌,老刑警劉巖巫延,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件效五,死亡現(xiàn)場離奇詭異,居然都是意外死亡炉峰,警方通過查閱死者的電腦和手機(jī)畏妖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疼阔,“玉大人戒劫,你說我怎么就攤上這事∑爬龋” “怎么了迅细?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長淘邻。 經(jīng)常有香客問我茵典,道長,這世上最難降的妖魔是什么宾舅? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任统阿,我火速辦了婚禮彩倚,結(jié)果婚禮上帆离,老公的妹妹穿的比我還像新娘蜻直。我一直安慰自己,他們只是感情好概而,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布赎瑰。 她就那樣靜靜地躺著,像睡著了一般压储。 火紅的嫁衣襯著肌膚如雪源譬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天刮刑,我揣著相機(jī)與錄音养渴,去河邊找鬼。 笑死理卑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的帆疟。 我是一名探鬼主播宇立,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼殴蓬!你這毒婦竟也來了蟋滴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤肖粮,失蹤者是張志新(化名)和其女友劉穎尔苦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體魂那,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涯雅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年展运,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔗候。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锈遥,死狀恐怖仰美,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情庆寺,我是刑警寧澤诉字,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布壤圃,位于F島的核電站,受9級特大地震影響伍绳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜效床,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一剩檀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沪猴,春花似錦、人聲如沸壶辜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽菠镇。三九已至,卻和暖如春利耍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背程癌。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工轴猎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锐峭。 一個(gè)月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓沿癞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親椎扬。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

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