日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM类加载机制详解(一)JVM类加载过程

發(fā)布時(shí)間:2024/1/17 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM类加载机制详解(一)JVM类加载过程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

首先Throws(拋出)幾個(gè)自己學(xué)習(xí)過程中一直疑惑的問題:

1、什么是類加載?什么時(shí)候進(jìn)行類加載?

2、什么是類初始化?什么時(shí)候進(jìn)行類初始化?

3、什么時(shí)候會為變量分配內(nèi)存?

4、什么時(shí)候會為變量賦默認(rèn)初值?什么時(shí)候會為變量賦程序設(shè)定的初值?

5、類加載器是什么?

6、如何編寫一個(gè)自定義的類加載器?

?

首先,在代碼編譯后,就會生成JVM(Java虛擬機(jī))能夠識別的二進(jìn)制字節(jié)流文件(*.class)。而JVM把Class文件中的類描述數(shù)據(jù)從文件加載到內(nèi)存,并對數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析、初始化,使這些數(shù)據(jù)最終成為可以被JVM直接使用的Java類型,這個(gè)說來簡單但實(shí)際復(fù)雜的過程叫做JVM的類加載機(jī)制

?

Class文件中的“類”從加載到JVM內(nèi)存中,到卸載出內(nèi)存過程有七個(gè)生命周期階段。類加載機(jī)制包括了前五個(gè)階段。

如下圖所示:

其中,加載、驗(yàn)證、準(zhǔn)備、初始化、卸載的開始順序是確定的,注意,只是按順序開始,進(jìn)行與結(jié)束的順序并不一定。解析階段可能在初始化之后開始。

?

另外,類加載無需等到程序中“首次使用”的時(shí)候才開始,JVM預(yù)先加載某些類也是被允許的。(類加載的時(shí)機(jī)

?

一、類的加載

我們平常說的加載大多不是指的類加載機(jī)制,只是類加載機(jī)制中的第一步加載。在這個(gè)階段,JVM主要完成三件事:

?

1、通過一個(gè)類的全限定名(包名與類名)來獲取定義此類的二進(jìn)制字節(jié)流(Class文件)。而獲取的方式,可以通過jar包、war包、網(wǎng)絡(luò)中獲取、JSP文件生成等方式。

2、將這個(gè)字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。這里只是轉(zhuǎn)化了數(shù)據(jù)結(jié)構(gòu),并未合并數(shù)據(jù)。(方法區(qū)就是用來存放已被加載的類信息,常量,靜態(tài)變量,編譯后的代碼的運(yùn)行時(shí)內(nèi)存區(qū)域)

3、在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口。這個(gè)Class對象并沒有規(guī)定是在Java堆內(nèi)存中,它比較特殊,雖為對象,但存放在方法區(qū)中。

?

二、類的連接

類的加載過程后生成了類的java.lang.Class對象,接著會進(jìn)入連接階段,連接階段負(fù)責(zé)將類的二進(jìn)制數(shù)據(jù)合并入JRE(Java運(yùn)行時(shí)環(huán)境)中。類的連接大致分三個(gè)階段。

1、驗(yàn)證:驗(yàn)證被加載后的類是否有正確的結(jié)構(gòu),類數(shù)據(jù)是否會符合虛擬機(jī)的要求,確保不會危害虛擬機(jī)安全。

2、準(zhǔn)備:為類的靜態(tài)變量(static filed)在方法區(qū)分配內(nèi)存,并賦默認(rèn)初值(0值或null值)。如static int a = 100;

靜態(tài)變量a就會在準(zhǔn)備階段被賦默認(rèn)值0。

對于一般的成員變量是在類實(shí)例化時(shí)候,隨對象一起分配在堆內(nèi)存中。

另外,靜態(tài)常量(static final filed)會在準(zhǔn)備階段賦程序設(shè)定的初值,如static final int a = 666; ?靜態(tài)常量a就會在準(zhǔn)備階段被直接賦值為666,對于靜態(tài)變量,這個(gè)操作是在初始化階段進(jìn)行的。

3、解析:將類的二進(jìn)制數(shù)據(jù)中的符號引用換為直接引用。

?

三、類的初始化

類初始化是類加載的最后一步,除了加載階段,用戶可以通過自定義的類加載器參與,其他階段都完全由虛擬機(jī)主導(dǎo)和控制。到了初始化階段才真正執(zhí)行Java代碼。

類的初始化的主要工作是為靜態(tài)變量賦程序設(shè)定的初值。

如static int a = 100;在準(zhǔn)備階段,a被賦默認(rèn)值0,在初始化階段就會被賦值為100。

?

Java虛擬機(jī)規(guī)范中嚴(yán)格規(guī)定了有且只有五種情況必須對類進(jìn)行初始化

1、使用new字節(jié)碼指令創(chuàng)建類的實(shí)例,或者使用getstatic、putstatic讀取或設(shè)置一個(gè)靜態(tài)字段的值(放入常量池中的常量除外),或者調(diào)用一個(gè)靜態(tài)方法的時(shí)候,對應(yīng)類必須進(jìn)行過初始化。

2、通過java.lang.reflect包的方法對類進(jìn)行反射調(diào)用的時(shí)候,如果類沒有進(jìn)行過初始化,則要首先進(jìn)行初始化。

3、當(dāng)初始化一個(gè)類的時(shí)候,如果發(fā)現(xiàn)其父類沒有進(jìn)行過初始化,則首先觸發(fā)父類初始化。

4、當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要指定一個(gè)主類(包含main()方法的類),虛擬機(jī)會首先初始化這個(gè)類。

5、使用jdk1.7的動(dòng)態(tài)語言支持時(shí),如果一個(gè)java.lang.invoke.MethodHandle實(shí)例最后的解析結(jié)果REF_getStatic、REF_putStatic、RE_invokeStatic的方法句柄,并且這個(gè)方法句柄對應(yīng)的類沒有進(jìn)行初始化,則需要先觸發(fā)其初始化。

?

注意,虛擬機(jī)規(guī)范使用了“有且只有”這個(gè)詞描述,這五種情況被稱為“主動(dòng)引用”,除了這五種情況,所有其他的類引用方式都不會觸發(fā)類初始化,被稱為“被動(dòng)引用”。

?

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

通過子類引用父類的靜態(tài)字段,對于父類屬于“主動(dòng)引用”的第一種情況,對于子類,沒有符合“主動(dòng)引用”的情況,故子類不會進(jìn)行初始化。代碼如下:

?

[java]?view plain?copy

  • //父類??
  • public?class?SuperClass?{??
  • ????//靜態(tài)變量value??
  • ????public?static?int?value?=?666;??
  • ????//靜態(tài)塊,父類初始化時(shí)會調(diào)用??
  • ????static{??
  • ????????System.out.println("父類初始化!");??
  • ????}??
  • }??
  • ??
  • //子類??
  • public?class?SubClass?extends?SuperClass{??
  • ????//靜態(tài)塊,子類初始化時(shí)會調(diào)用??
  • ????static{??
  • ????????System.out.println("子類初始化!");??
  • ????}??
  • }??
  • ??
  • //主類、測試類??
  • public?class?NotInit?{??
  • ????public?static?void?main(String[]?args){??
  • ????????System.out.println(SubClass.value);??
  • ????}??
  • }??
  • 輸出結(jié)果:

    ?

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

    通過數(shù)組來引用類,不會觸發(fā)類的初始化,因?yàn)槭菙?shù)組new,而類沒有被new,所以沒有觸發(fā)任何“主動(dòng)引用”條款,屬于“被動(dòng)引用”。代碼如下:

    ?

    [java]?view plain?copy

  • //父類??
  • public?class?SuperClass?{??
  • ????//靜態(tài)變量value??
  • ????public?static?int?value?=?666;??
  • ????//靜態(tài)塊,父類初始化時(shí)會調(diào)用??
  • ????static{??
  • ????????System.out.println("父類初始化!");??
  • ????}??
  • }??
  • ??
  • //主類、測試類??
  • public?class?NotInit?{??
  • ????public?static?void?main(String[]?args){??
  • ????????SuperClass[]?test?=?new?SuperClass[10];??
  • ????}??
  • }??
  • ?

    ?

    沒有任何結(jié)果輸出!

    ?

    ?

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

    剛剛講解時(shí)也提到,靜態(tài)常量在編譯階段就會被存入調(diào)用類的常量池中,不會引用到定義常量的類,這是一個(gè)特例,需要特別記憶,不會觸發(fā)類的初始化!

    ?

    [java]?view plain?copy

  • //常量類??
  • public?class?ConstClass?{??
  • ????static{??
  • ????????System.out.println("常量類初始化!");??
  • ????}??
  • ??????
  • ????public?static?final?String?HELLOWORLD?=?"hello?world!";??
  • }??
  • ??
  • //主類、測試類??
  • public?class?NotInit?{??
  • ????public?static?void?main(String[]?args){??
  • ????????System.out.println(ConstClass.HELLOWORLD);??
  • ????}??
  • }??
  • ?

    轉(zhuǎn)載于:https://my.oschina.net/u/2543341/blog/1504033

    總結(jié)

    以上是生活随笔為你收集整理的JVM类加载机制详解(一)JVM类加载过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。