java類加載機(jī)制

虛擬機(jī)把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存浙于,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換挟纱、解析和初始化羞酗,最終可以變成被虛擬機(jī)使用的Java類型,這就是虛擬機(jī)的類加載機(jī)制紊服。

在java中檀轨,類型的加載、連接和初始化都是在程序運(yùn)行期間完成的欺嗤,不同于c/c++,這種策略的缺點(diǎn)就是在類加載的時(shí)候會(huì)造成性能開(kāi)銷参萄,但是它保證了java應(yīng)用程序的靈活性。例如:用戶可以通過(guò)自定義的類加載器煎饼,讓一個(gè)應(yīng)用程序可以在運(yùn)行時(shí)從網(wǎng)絡(luò)或者其它地方加載一個(gè)二進(jìn)制流作為程序代碼的一部分拧揽。例如JSP技術(shù)。

一腺占、類的加載時(shí)機(jī)與過(guò)程

1. 類的加載時(shí)機(jī)

類從被加載到虛擬機(jī)內(nèi)存中開(kāi)始淤袜,直到卸載出內(nèi)存為止,它的整個(gè)生命周期包括了:加載衰伯、驗(yàn)證铡羡、準(zhǔn)備、解析意鲸、初始化烦周、使用和卸載這7個(gè)階段尽爆。其中,驗(yàn)證读慎、準(zhǔn)備和解析這三個(gè)部分統(tǒng)稱為連接(linking)漱贱。

類的加載時(shí)機(jī).jpg

2. 何時(shí)開(kāi)始類的初始化

什么情況下需要開(kāi)始類加載過(guò)程的第一個(gè)階段:"加載"。虛擬機(jī)規(guī)范中并沒(méi)強(qiáng)行約束夭委,這點(diǎn)可以交給虛擬機(jī)的的具體實(shí)現(xiàn)自由把握幅狮,但是對(duì)于初始化階段虛擬機(jī)規(guī)范是嚴(yán)格規(guī)定了如下幾種情況,如果類未初始化會(huì)對(duì)類進(jìn)行初始化株灸。

  • 創(chuàng)建類的實(shí)例
  • 訪問(wèn)類的靜態(tài)變量(除常量即被final表示的靜態(tài)變量)崇摄,因?yàn)?strong>常量一種特殊的變量,因?yàn)榫幾g器把他們當(dāng)作值(value)而不是域(field)來(lái)對(duì)待慌烧。如果你的代碼中用到了常變量(constant variable)逐抑,編譯器并不會(huì)生成字節(jié)碼來(lái)從對(duì)象中載入域的值,而是直接把這個(gè)值插入到字節(jié)碼中屹蚊。這是一種很有用的優(yōu)化厕氨,但是如果你需要改變final域的值那么每一塊用到那個(gè)域的代碼都需要重新編譯。
  • 訪問(wèn)類的靜態(tài)方法
  • 反射(Class.forName("com.zcl.main"))
  • 當(dāng)初始化一個(gè)類時(shí)汹粤,發(fā)現(xiàn)其父類還未初始化腐巢,則先對(duì)父類進(jìn)行初始化
  • 虛擬機(jī)啟動(dòng)時(shí),先對(duì)main()方法的那個(gè)類進(jìn)行初始化
    以上情況稱為稱對(duì)一個(gè)類進(jìn)行“主動(dòng)引用”玄括,除此種情況之外冯丙,均不會(huì)觸發(fā)類的初始化,稱為“被動(dòng)引用”
    接口的加載過(guò)程與類的加載過(guò)程稍有不同遭京。接口中不能使用static{}塊胃惜。當(dāng)一個(gè)接口在初始化時(shí),并不要求其父接口全部都完成了初始化哪雕,只有真正在使用到父接口時(shí)(例如引用接口中定義的常量)才會(huì)初始化船殉。

被動(dòng)引用的例子

  1. 子類調(diào)用父類的靜態(tài)變量,子類不會(huì)被初始化斯嚎。只有父類被初始化利虫。。對(duì)于靜態(tài)字段堡僻,只有直接定義這個(gè)字段的類才會(huì)被初始化.
  2. 通過(guò)數(shù)組定義來(lái)引用類糠惫,不會(huì)觸發(fā)類的初始化
  3. 訪問(wèn)類的常量,不會(huì)初始化類
class SuperClass {
    static {
        System.out.println("superclass init");
    }
    public static int value = 123;
}
 
class SubClass extends SuperClass {
    static {
        System.out.println("subclass init");
    }
}
 
public class Test {
    public static void main(String[] args) {
        System.out.println(SubClass.value);// 被動(dòng)應(yīng)用1
        SubClass[] sca = new SubClass[10];// 被動(dòng)引用2
    }
}

程序輸出:證明了被動(dòng)引用1 2
superclass init
123

class ConstClass {
    static {
        System.out.println("ConstClass init");
    }
    public static final String HELLOWORLD = "hello world";
}
 
public class Test {
    public static void main(String[] args) {
        System.out.println(ConstClass.HELLOWORLD);// 調(diào)用類常量
    }
}

程序輸出:證明了被動(dòng)引用3
hello world

2. 類的加載過(guò)程

2.1驗(yàn)證

驗(yàn)證class文件的內(nèi)容是否符合jvm虛擬機(jī)的標(biāo)準(zhǔn)要求钉疫,包括class文件的格式驗(yàn)證和語(yǔ)義驗(yàn)證等

2.2 準(zhǔn)備

準(zhǔn)備階段是為類的靜態(tài)變量分配內(nèi)存并將其初始化為默認(rèn)值硼讽,這些內(nèi)存都將在方法區(qū)中進(jìn)行分配。準(zhǔn)備階段不分配類中的實(shí)例變量的內(nèi)存牲阁,實(shí)例變量將會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一起分配在Java堆中固阁。

public static int value=123;//在準(zhǔn)備階段value初始值為0 壤躲。在初始化階段才會(huì)變?yōu)?23 。

2.3 解析

該階段主要完成符號(hào)引用到直接引用的轉(zhuǎn)換動(dòng)作备燃,例如:根據(jù)類的全限定名找到該類具體的地址碉克。解析動(dòng)作并不一定在初始化動(dòng)作完成之前,也有可能在初始化之后并齐。

2.4 初始化

初始化順序:
我們大家都知道漏麦,對(duì)于靜態(tài)變量、靜態(tài)初始化塊冀膝、變量、初始化塊霎挟、構(gòu)造器窝剖,它們的初始化順序以此是(靜態(tài)變量、靜態(tài)初始化塊)>(變量酥夭、初始化塊)>構(gòu)造器赐纱。

類初始化是類加載過(guò)程的最后一步,前面的類加載過(guò)程熬北,除了在加載階段用戶應(yīng)用程序可以通過(guò)自定義類加載器參與之外疙描,其余動(dòng)作完全由虛擬機(jī)主導(dǎo)和控制。到了初始化階段讶隐,才真正開(kāi)始執(zhí)行類中定義的Java程序代碼起胰。

初始化階段是執(zhí)行類構(gòu)造器<clinit>()方法的過(guò)程。<clinit>()方法是由編譯器自動(dòng)收集類中的所有類變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊(static{}塊)中的語(yǔ)句合并產(chǎn)生的巫延。


題目分析

class SingleTon {
    private static SingleTon singleTon = new SingleTon();
    public static int count1;
    public static int count2 = 0;
 
    private SingleTon() {
        count1++;
        count2++;
    }
 
    public static SingleTon getInstance() {
        return singleTon;
    }
}
 
public class Test {
    public static void main(String[] args) {
        SingleTon singleTon = SingleTon.getInstance();
        System.out.println("count1=" + singleTon.count1);
        System.out.println("count2=" + singleTon.count2);
    }
}

1:SingleTon singleTon = SingleTon.getInstance();調(diào)用了類的SingleTon調(diào)用了類的靜態(tài)方法效五,觸發(fā)類的初始化
2:類加載的時(shí)候在準(zhǔn)備過(guò)程中為類的靜態(tài)變量分配內(nèi)存并初始化默認(rèn)值 singleton=null count1=0,count2=0
3:類初始化,為類的靜態(tài)變量賦值和執(zhí)行靜態(tài)代碼塊炉峰。singleton賦值為new SingleTon()調(diào)用類的構(gòu)造方法
4:調(diào)用類的構(gòu)造方法后count=1;count2=1
5:繼續(xù)為count1與count2賦值,此時(shí)count1沒(méi)有賦值操作,所有count1為1,但是count2執(zhí)行賦值操作就變?yōu)?
若將代碼修改為下

class Singleton {
    private static Singleton singleTon = new Singleton();
    public static int count1 = 1;
    public int count2 = 2 ;

    private Singleton() {
        System.out.println(count1 + " - "+count2);
        count1++;
        count2++;
    }

    public static Singleton getInstance() {
        return singleTon;
    }
}

public class Test {
    public static void main(String[] args) {
        Singleton singleTon = Singleton.getInstance();
        System.out.println("count1=" + singleTon.count1);
        System.out.println("count2=" + singleTon.count2);
    }
}

則有結(jié)果為:

0 - 2
count1=1
count2=3

分析:因?yàn)槠胀ǔA恐挥性趯?duì)象被實(shí)例化后才分配內(nèi)存空間進(jìn)行賦值畏妖,所有當(dāng)進(jìn)行new Sigleton()時(shí),count2已經(jīng)被賦值為2疼阔,而靜態(tài)變量在類加載的準(zhǔn)備階段已經(jīng)被初始化為0戒劫,這時(shí)還沒(méi)有被進(jìn)行賦值操作,所以最終結(jié)果為賦值后的結(jié)果1

本文摘自https://blog.csdn.net/m0_38075425/article/details/81627349
https://www.cnblogs.com/shinubi/articles/6116993.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末婆廊,一起剝皮案震驚了整個(gè)濱河市迅细,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淘邻,老刑警劉巖疯攒,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異列荔,居然都是意外死亡敬尺,警方通過(guò)查閱死者的電腦和手機(jī)枚尼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)砂吞,“玉大人署恍,你說(shuō)我怎么就攤上這事◎咧保” “怎么了盯质?”我有些...
    開(kāi)封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)概而。 經(jīng)常有香客問(wèn)我呼巷,道長(zhǎng),這世上最難降的妖魔是什么赎瑰? 我笑而不...
    開(kāi)封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任王悍,我火速辦了婚禮,結(jié)果婚禮上餐曼,老公的妹妹穿的比我還像新娘压储。我一直安慰自己,他們只是感情好源譬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布集惋。 她就那樣靜靜地躺著,像睡著了一般踩娘。 火紅的嫁衣襯著肌膚如雪刮刑。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天养渴,我揣著相機(jī)與錄音为朋,去河邊找鬼。 笑死厚脉,一個(gè)胖子當(dāng)著我的面吹牛习寸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播傻工,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼霞溪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了中捆?” 一聲冷哼從身側(cè)響起鸯匹,我...
    開(kāi)封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎泄伪,沒(méi)想到半個(gè)月后殴蓬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年染厅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痘绎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肖粮,死狀恐怖孤页,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涩馆,我是刑警寧澤行施,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站魂那,受9級(jí)特大地震影響蛾号,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜涯雅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一鲜结、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧斩芭,春花似錦轻腺、人聲如沸乐疆。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挤土。三九已至琴庵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間仰美,已是汗流浹背迷殿。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留咖杂,地道東北人庆寺。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像诉字,于是被迫代替她去往敵國(guó)和親懦尝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355