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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

类加载机制--浅谈

發(fā)布時間:2025/3/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 类加载机制--浅谈 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、定義:

? ? 類加載(Class Loading)是一種機制,他描述的是將字節(jié)碼以文件形式加載到內(nèi)存再經(jīng)過連接、初始化后,最終形成可以被虛擬機直接使用的Java類型地過程。

? ? Class Loading 包含了加載(Loading)、連接(Linking)、初始化(Initialization)三大部分,其中Linking又包含了三個部分:校驗(Verification)、準(zhǔn)備? (Preparation)、解析(Resolution)。而一個類的生命周期只是在Class Loader的基礎(chǔ)上多了:使用(Using),卸載(Unloading)兩部分。

Class Loaders的組成:

二、加載階段

虛擬機需要完成以下3件事情:

1)通過一個類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。

2)將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。

3)在內(nèi)存中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口。

注意:

? ? 1.JVM在加載數(shù)組的時候加載的僅僅是數(shù)組的類型類(例如String[] 加載器只會加載String這個類型類),而數(shù)組的創(chuàng)建則由JVM直接完成。

這里我們多問幾個為什么:
? ? 2. JVM為什么只加載數(shù)組的類型類:
我認(rèn)為JVM這樣做的目的主要是為了節(jié)省時間,我們知道數(shù)組里面裝的都是同一種類型的元素,JVM沒必要將一個重復(fù)的內(nèi)容加載多次浪費時間。
? ? 3. N維數(shù)組怎么加載:
如果是N維數(shù)組,類加載器會從最外層開始一層一層的遞歸加載,直到加載到非數(shù)組類型為止。
? ? 4. 引用類型與基本類型加載起來會不會有區(qū)別:
其實基本類型早已經(jīng)在javac階段裝箱成封裝對象了,例如int會被裝箱成Integer,long裝箱成Long等等,所以是沒有區(qū)別的。

三、驗證

? ? ? 驗證是連接階段的第一步,這一階段目的是為了確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機的要求,并且不會危害虛擬機自身安全。

? ? ? 虛擬機規(guī)范對這個階段的限制和指導(dǎo)非常籠統(tǒng),僅僅說了一句如果驗證到輸入的字節(jié)流不符合Class文件的存儲格式,就拋出一個java.lang.VerifyError異常或者其子類異常。具體應(yīng)當(dāng)檢查哪些方面,如何檢查,何時檢查,都沒有強制要求或明確說明,所以不同的虛擬機對驗證的實現(xiàn)可能會有所不同,但大致上都會完場下面四個階段的檢驗過程:文件格式驗證、元數(shù)據(jù)驗證、字節(jié)碼驗證和符號引用驗證。

? ? ? ? 是連接階段的第一步,這一階段的目的是為了確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機的要求,并且不會危害虛擬機自身的安全。但從整體上看,驗證階段大致上會完成下面4個階段的檢驗動作:文件格式驗證、元數(shù)據(jù)驗證、字節(jié)碼驗證、符號引用驗證。

  • 文件格式驗證:驗證字節(jié)流是否符合Class文件格式的規(guī)范;例如:是否以魔術(shù)0xCAFEBABE開頭、主次版本號是否在當(dāng)前虛擬機的處理范圍之內(nèi)、常量池中的常量是否有不被支持的類型。
  • 元數(shù)據(jù)驗證:對字節(jié)碼描述的信息進(jìn)行語義分析(注意:對比javac編譯階段的語義分析),以保證其描述的信息符合Java語言規(guī)范的要求;例如:這個類是否有父類,除了java.lang.Object之外。
  • 字節(jié)碼驗證:通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的、符合邏輯的。
  • 符號引用驗證:確保解析動作能正確執(zhí)行。
  • 四、準(zhǔn)備階段

    ? ? ? ?是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。

    ? ? ? ?這個階段中有兩個容易產(chǎn)生混淆的概念需要強調(diào)一下,首先,這時候進(jìn)行內(nèi)存分配的僅包括類變量(被static修飾的變量),而不包括實例變量,實例變量將會在對象實例化時隨著對象一起分配在Java堆中。其次,這里所說的初始值“通常情況”下是數(shù)據(jù)類型的零值,假設(shè)一個類變量的定義為:

    public static int value=123;

    那變量value在準(zhǔn)備階段過后的初始值為0而不是123,因為這時候尚未開始執(zhí)行任何Java方法,而把value賦值為123的putstatic指令是程序被編譯后,存放于類構(gòu)造器<clinit>()方法之中,所以把value賦值為123的動作將在初始化階段才會執(zhí)行。表7-1列出了Java中所有基本數(shù)據(jù)類型的零值。

    假設(shè)上面類變量value的定義變?yōu)?#xff1a;public static final int value=123;

    編譯時Javac將會為value生成ConstantValue屬性,在準(zhǔn)備階段虛擬機就會根據(jù)ConstantValue的設(shè)置將value賦值為123。

    五、解析階段

    是虛擬機將常量池內(nèi)的符號引用替換為直接引用的過程

    六、初始化

    在連接的準(zhǔn)備階段,類變量已賦過一次系統(tǒng)要求的初始值,而在初始化階段,則是根據(jù)程序員自己寫的邏輯去初始化類變量和其他資源,舉個例子如下:

    public static int value1 = 5;public static int value2 = 6;static{value2 = 66;}

    在準(zhǔn)備階段value1和value2都等于0;

    在初始化階段value1和value2分別等于5和66;

    • 所有類變量(類變量是聲明在class內(nèi),method之外,且使用static修飾的變量)初始化語句和靜態(tài)代碼塊都會在編譯時被前端編譯器放在收集器里頭,存放到一個特殊的方法中,這個方法就是<clinit>方法,即類/接口初始化方法,該方法只能在類加載的過程中由JVM調(diào)用;
    • 編譯器收集的順序是由語句在源文件中出現(xiàn)的順序所決定的,靜態(tài)語句塊中只能訪問到定義在靜態(tài)語句塊之前的變量;
    • 如果超類還沒有被初始化,那么優(yōu)先對超類初始化,但在<clinit>方法內(nèi)部不會顯示調(diào)用超類的<clinit>方法,由JVM負(fù)責(zé)保證一個類的<clinit>方法執(zhí)行之前,它的超類<clinit>方法已經(jīng)被執(zhí)行。
    • JVM必須確保一個類在初始化的過程中,如果是多線程需要同時初始化它,僅僅只能允許其中一個線程對其執(zhí)行初始化操作,其余線程必須等待,只有在活動線程執(zhí)行完對類的初始化操作之后,才會通知正在等待的其他線程。(所以可以利用靜態(tài)內(nèi)部類實現(xiàn)線程安全的單例模式)
    • 如果一個類沒有聲明任何的類變量,也沒有靜態(tài)代碼塊,那么可以沒有類<clinit>方法;

    何時觸發(fā)初始化

  • 為一個類型創(chuàng)建一個新的對象實例時(比如new、反射、序列化)
  • 調(diào)用一個類型的靜態(tài)方法時(即在字節(jié)碼中執(zhí)行invokestatic指令)
  • 調(diào)用一個類型或接口的靜態(tài)字段,或者對這些靜態(tài)字段執(zhí)行賦值操作時(即在字節(jié)碼中,執(zhí)行g(shù)etstatic或者putstatic指令),不過用final修飾的靜態(tài)字段除外,它被初始化為一個編譯時常量表達(dá)式
  • 調(diào)用JavaAPI中的反射方法時(比如調(diào)用java.lang.Class中的方法,或者java.lang.reflect包中其他類的方法)
  • 初始化一個類的派生類時(Java虛擬機規(guī)范明確要求初始化一個類時,它的超類必須提前完成初始化操作,接口例外)
  • JVM啟動包含main方法的啟動類時。
  • 七、系統(tǒng)的類加載器

    類加載器名稱

    加載的范圍

    啟動類加載器

    Bootstrap ClassLoader

    存放在<JAVA_HOME>\lib目錄中的,并且是虛擬機 識別的類庫加載到虛擬機內(nèi)存中

    擴展類加載器 Extension ClassLoader

    存放在<JAVA_HOME>\lib\ext目錄中的所有類庫, 開發(fā)者可以直接使用;

    應(yīng)用程序加載器 Application ClassLoader

    加載用戶類路徑上指定的類庫,開發(fā)者可以直 接使用,一般情況下這個就是程序中默認(rèn)的類 加載器;

    八、雙親委派機制

    ? ? ? ? 某個特定的類加載器在接到加載類的請求 時,首先將加載任務(wù)委托給父類加載器, 依次遞歸,如果父類加載器可以完成類加 載任務(wù),就成功返回;只有父類加載器無 法完成此加載任務(wù)時,才自己去加載

    ? ? ? ? 雙親委派模型好處:Java類隨著它的類加載器一起具備了帶 有優(yōu)先級的層次關(guān)系,保證java程序穩(wěn) 定運行

    九、示例代碼

    public class SuperClazz {public SuperClazz(){System.out.println("我是父類構(gòu)造方法");}static {System.out.println("我是父類靜態(tài)代碼塊");}public static int value = 123;public static final String STR = "hello world";public static final int WHAT = value; }public class SonClazz extends SuperClazz {public SonClazz(){System.out.println("我是子類構(gòu)造方法");}static {System.out.println("我是子類靜態(tài)代碼塊");} }
    public class DemoTest {
    public static void main(String args[]){ /* System.out.println(SonClazz.value);
    輸出結(jié)果:
    我是父類靜態(tài)代碼塊
    123
    結(jié)論:對于靜態(tài)字段,只有直接定義這個字段的類,才能被初始化。
    */
    /*
    SuperClazz[] aa = new SuperClazz[10];
    輸出結(jié)果:(什么也沒有輸出)
    結(jié)論:只是聲明了一個數(shù)組形式的變量,類沒有初始化
    */

    /*
    System.out.println(SonClazz.STR);
    輸出結(jié)果:hello world
    結(jié)論:編譯期的傳播優(yōu)化,因為是常量,所以就會直接編譯到了運行的類里面,就不會再去定義的類里面找了
    ,STR還是在常量池里面的;
    */

         /**

          我是父類靜態(tài)代碼塊
          123

        */
    //System.out.println(SonClazz.WHAT);


    } ? public class DemoTest2 {static{i=0;System.out.println(i);//這句編譯器會報錯:Cannot reference a field before it is defined(非法向前應(yīng)用) }static int i=1; } public class DemoTest2 {static{i=2; // System.out.println(i); }static int i=1;public static void main(String args[]){System.out.println(i);} }輸出結(jié)果:1

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/lys-lyy/p/10771751.html

    總結(jié)

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

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