您好,登錄后才能下訂單哦!
前言
不了解JVM的類加載機(jī)制你也可以coding,但是當(dāng)你了解之后,可以讓你在coding的時候避免很多坑,本文將以一道常見的面試題去剖析一下。本文參考 深入理解Java虛擬機(jī)(第2版) 。
1 public class ClassLoadTest {
2 private static ClassLoadTest test = new ClassLoadTest();
3
4 static int x;
5 static int y = 0;
6
7 public ClassLoadTest() {
8 x++;
9 y++;
10 }
11
12 public static void main(String[] args) {
13 System.out.println(test.x);
14 System.out.println(test.y);
15 }
16}
這里大家可以先猜測一下答案,可能結(jié)果會出乎你的意料~
類加載過程
先用一個圖簡單的描述一下類加載的這個過程
加載
這個過程相當(dāng)于從本地或者網(wǎng)絡(luò)端去讀取一個字節(jié)流,然后將一些靜態(tài)儲存結(jié)構(gòu)轉(zhuǎn)換成方法區(qū)中運(yùn)行時期的數(shù)據(jù),最后生成一個代表這個類的Class對象,作為方法區(qū)訪問這個類的入口。
例如:
咱們可以通過一個類的全限定名去加載類
通過jar、war包去加載類
通過http請求去第三方平臺上拉取指定的類來加載
針對上述例子,這里是加載一個?ClassLoadTest.class
?對象。
驗證
要理解這個環(huán)節(jié)并不是很難,一個東西要放到JVM上去運(yùn)行,咱們肯定得對其進(jìn)行一些過濾,不能啥都往上丟,這里的驗證簡單的舉幾個例子:
文件格式的驗證:?
①是否以魔數(shù)0xCAFEBABE開頭;?
②主次版本號是否在當(dāng)前虛擬機(jī)處理范圍內(nèi);?
③常量池中的常量是否有不被支持的常量類型等等。
元數(shù)據(jù)的驗證:?
①這個類是否有父類;?
②這個類的父類是否繼承了不被允許繼承的類(final修飾的類);?
③這個類不是抽象類,是否實(shí)現(xiàn)了所有接口中要實(shí)現(xiàn)的方法等等。
字節(jié)碼的驗證:
①保證跳轉(zhuǎn)指令不會跳轉(zhuǎn)到方法體以外的字節(jié)碼指令上;?
②保證方法體中的類型轉(zhuǎn)換是有效的等等。
準(zhǔn)備過程
這個過程相當(dāng)于給類變量分配內(nèi)存并設(shè)置變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。
針對上述例子:
1test = null;
2x = 0;
3y = 0;
注意:這里有個特殊情況,如果該字段被?final
?修飾,那么在準(zhǔn)備階段改字段就會被設(shè)置成咱們自定義的值。?public static final int?value?= 11
?,在準(zhǔn)備階段就會直接賦值11,并不是該變量的初始值。
解析過程
將符號引用轉(zhuǎn)換成直接引用的過程。這里有兩個名詞?符號引用?和?直接引用?。
符號引用:符號引用與虛擬機(jī)的布局無關(guān),甚至引用的目標(biāo)不一定加載到了內(nèi)存中。符號可以是任何形式的字面量,只要使用時能夠準(zhǔn)確的定位到目標(biāo)即可。
而解析過程又會針對類、字段、方法進(jìn)行解析,解析失敗則會拋出相應(yīng)的異常。例如在解析時發(fā)現(xiàn)沒有訪問權(quán)限會拋出?java.lang.IllegalAccessException
?異常,查詢不到引用字段會拋出?java.lang.NoSuchFieldException
?異常,查詢不到方法會拋出?java.lang.NoSuchMethodException
?異常等等。
初始化
在準(zhǔn)備階段,變量已經(jīng)賦值過系統(tǒng)要求的默認(rèn)值,在初始化階段,則會根據(jù)程序制定的主觀計劃去初始化類變量和其他資源。這句話聽起來有些繞口,根據(jù)上述例子,實(shí)際上就是:
1test = new ClassLoadTest();// x = 1;y =1
2y = 0;
這個過程,由于?x
?咱們自己并沒有去設(shè)定一個值,所以初始化階段它不會發(fā)生任何改變,但是?y
?咱們有設(shè)定一個值0,所以最后造成最終結(jié)果為?x = 1;y = 0
?。
ps:在同一個類加載器下,一個類只會初始化一次。多個線程同時初始化一個類,只有一個線程能正常初始化,其他線程都會進(jìn)行阻塞等待,直到活動線程執(zhí)行初始化方法完畢。
總結(jié)
對于上面這個面試題,咱們用流程圖簡單的描述一下:
對Java技術(shù),架構(gòu)技術(shù)感興趣的同學(xué),歡迎加群,一起學(xué)習(xí),相互討論??梢垣@取免費(fèi)的學(xué)習(xí)資料,群號:614478470 點(diǎn)擊加入
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。