類加載共有以下步驟,如圖:
1.加載:
把class文件讀入虛擬機(jī),轉(zhuǎn)換成為運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu),也就是InstanceClass,InstanceClass是C++實(shí)現(xiàn)的JVM中表示一個(gè)java Class的,同時(shí)java class文件中的每個(gè)方法也會(huì)轉(zhuǎn)換為C++的Method對(duì)象.
記住:
1>.C++也是面向?qū)ο蟮模灿蓄惡蛯?duì)象的概念
2>.還有一件事就是把元信息保存到方法區(qū)里,也就是諸如方法的字節(jié)碼指令
- 驗(yàn)證:
驗(yàn)證的目的是為了確保Class文件的字節(jié)流中的信息不會(huì)危害到虛擬機(jī);
文件格式驗(yàn)證 :驗(yàn)證字節(jié)流是否符合Class文件的規(guī)范,如主次版本號(hào)是否在當(dāng)前虛擬機(jī)范圍內(nèi),常量池中的常量是否有不被支持的類型等等;
元數(shù)據(jù)驗(yàn)證 :對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析,如這個(gè)類是否有父類,是否繼承了不被繼承的類等等;
字節(jié)碼驗(yàn)證 :通過驗(yàn)證數(shù)據(jù)流和控制流的分析,確定程序語(yǔ)義是否正確,主要針對(duì)方法體的驗(yàn)證。如:方法中的類型轉(zhuǎn)換是否正確,跳轉(zhuǎn)指令是否正確等等;
符號(hào)引用驗(yàn)證 :為了確保解析動(dòng)作能正確執(zhí)行;
- 準(zhǔn)備:
簡(jiǎn)單理解就是給static成員分配空間,已經(jīng)賦值,注意是零值。比如int是0,long是0L。
4 .解析:
符號(hào)引用替換為直接引用。就是說我要執(zhí)行一個(gè)方法,字節(jié)碼一般都是這么個(gè)格式的invokevirtual #7。其中#7是常量表的第七個(gè)常量。但是這個(gè)常量只是一個(gè)字面量,實(shí)際代碼要能夠找到它要執(zhí)行的方法的地址,解析就是干這個(gè)的
- 初始化:
這個(gè)步驟才是執(zhí)行我們自己寫的代碼的階段了。如果一個(gè)類里有static成員或者static代碼塊,編譯器變出來的class文件會(huì)自動(dòng)多出來一個(gè)clinit方法,也就是說對(duì)于static成員的賦值是在這里做的。
初始化:在準(zhǔn)備階段已經(jīng)對(duì)類變量進(jìn)行初始化了,這里的初始化是執(zhí)行類構(gòu)造器<clinit>。
<clinit>()方法是編譯器自動(dòng)收集類中所有類變量的賦值動(dòng)作和靜態(tài)代碼塊而產(chǎn)生的方法(無論類變量和靜態(tài)代碼塊的位置是什么樣,都是先執(zhí)行類變量的賦值動(dòng)作,再執(zhí)行靜態(tài)代碼塊) 這里特別需要注意的是,初始化只是執(zhí)行clinit而不是init,加載class并不是創(chuàng)建一個(gè)對(duì)象