最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

聊一聊Java的JVM類加載機(jī)制

 更新時(shí)間:2023年04月20日 10:40:14   作者:索碼理  
這篇文章主要介紹了聊一聊Java的JVM類加載機(jī)制,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

Java虛擬機(jī)把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直接使用的Java類型,這個(gè)過(guò)程被稱作虛擬機(jī)的類加載機(jī)制。當(dāng)Java程序運(yùn)行時(shí),Java虛擬機(jī)會(huì)按需加載類,即在程序需要使用某個(gè)類時(shí)才會(huì)加載該類。

類的生命周期如下圖:

類的生命周期

JVM的類加載機(jī)制包括加載、連接( 驗(yàn)證、準(zhǔn)備、解析)、初始化 3個(gè)階段。

加載(Loading)

加載(Loading) 階段主要是查找并加載字節(jié)碼文件,這個(gè)文件可以是來(lái)自本地文件系統(tǒng)、網(wǎng)絡(luò)、jar包等地方。加載后,生成一個(gè)對(duì)應(yīng)的Class對(duì)象。

加載類時(shí)會(huì)做以下工作:

  1. 根據(jù)類的全限定名查找并讀取類的二進(jìn)制數(shù)據(jù)。類的二進(jìn)制數(shù)據(jù)可以來(lái)自文件、網(wǎng)絡(luò)、數(shù)據(jù)庫(kù)等各種數(shù)據(jù)源。
  2. 將類的二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成方法區(qū)內(nèi)部的數(shù)據(jù)結(jié)構(gòu)。在轉(zhuǎn)換的過(guò)程中,JVM會(huì)對(duì)類的二進(jìn)制數(shù)據(jù)進(jìn)行解析和校驗(yàn)。
  3. 在方法區(qū)內(nèi)存儲(chǔ)該類的相關(guān)信息,包括類的名稱、修飾符、常量池、字段描述符、方法描述符、接口描述符、方法表等。
  4. 生成一個(gè)代表該類的Class對(duì)象,并將該對(duì)象存放在JVM的堆內(nèi)存中。Class對(duì)象包含了類的各種信息,可以用于創(chuàng)建類的實(shí)例、獲取類的方法和字段等操作。

需要注意的是,在加載類的過(guò)程中,JVM會(huì)遵循一定的雙親委派機(jī)制,即先委派給父類加載器嘗試加載,如果父類加載器無(wú)法加載,則由當(dāng)前類加載器進(jìn)行加載。這樣可以保證類的加載不會(huì)重復(fù),避免出現(xiàn)類似的類被多次加載的情況。有關(guān)類加載器可以查看我之前的文章。

加載階段與連接階段的部分動(dòng)作(如一部分字節(jié)碼文件格式驗(yàn)證動(dòng)作)是交叉進(jìn)行的,加載階段尚未完成,連接階段可能已經(jīng)開(kāi)始,但這些夾在加載階段之中進(jìn)行的動(dòng)作,仍然屬于連接階段的一部分,這兩個(gè)階段的開(kāi)始時(shí)間仍然保持著固定的先后順序。

連接(Linking)

連接階段是Java虛擬機(jī)將類文件中的符號(hào)引用轉(zhuǎn)換為直接引用的過(guò)程,會(huì)對(duì)字節(jié)碼文件進(jìn)行驗(yàn)證、準(zhǔn)備、解析。

  • 驗(yàn)證(Verification):在這個(gè)階段,JVM會(huì)對(duì)字節(jié)碼進(jìn)行驗(yàn)證,以確保其符合Java虛擬機(jī)規(guī)范,并且不會(huì)對(duì)虛擬機(jī)造成安全威脅。驗(yàn)證的內(nèi)容包括靜態(tài)分析、字節(jié)碼驗(yàn)證、符號(hào)引用驗(yàn)證等。如果驗(yàn)證失敗,JVM會(huì)拋出VerifyError異常。
  • 準(zhǔn)備(Preparation):在這個(gè)階段,JVM會(huì)為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值(零值)。這個(gè)階段不會(huì)執(zhí)行任何Java代碼,只是為靜態(tài)變量分配內(nèi)存空間。例如將int類型的靜態(tài)變量賦值為0。
public static int staticValue = 123;

準(zhǔn)備階段初始化只是將靜態(tài)變量初始化為默認(rèn)值,比如上面這段代碼,不同數(shù)據(jù)類型都有其默認(rèn)值,初始化是只是將staticValue賦予默認(rèn)值0,也就是staticValue = 0,只有在初始化階段才會(huì)將staticValue賦值為123,也就是staticValue = 123。但是如果是staticValue是個(gè)常量public static final int staticValue = 123,準(zhǔn)備階段才會(huì)將staticValue賦值為123。

  • 解析(Resolution):在這個(gè)階段,JVM會(huì)將類、接口、字段和方法的符號(hào)引用解析為直接引用符號(hào)引用是指用來(lái)描述某個(gè)類、字段或方法的名稱和類型的符號(hào),而直接引用則是指直接指向內(nèi)存中的具體位置的引用。解析的過(guò)程包括將類或接口的符號(hào)引用解析為直接引用、將字段的符號(hào)引用解析為直接引用、將類中方法的符號(hào)引用解析為直接引用。

初始化(Initialization)

初始化階段是指在類被首次主動(dòng)使用時(shí)執(zhí)行的階段,虛擬機(jī)會(huì)執(zhí)行類的初始化代碼,包括靜態(tài)變量的賦值和靜態(tài)代碼塊的執(zhí)行等操作。

初始化階段是類加載的最后一個(gè)階段,在該階段,JVM會(huì)執(zhí)行以下操作:

  1. 執(zhí)行靜態(tài)變量賦值操作:在這個(gè)階段,JVM會(huì)對(duì)所有的靜態(tài)變量進(jìn)行初始化并賦值。這些靜態(tài)變量的值通常在類定義中已經(jīng)被明確定義了,JVM會(huì)根據(jù)定義進(jìn)行相應(yīng)的賦值操作。
  2. 執(zhí)行靜態(tài)代碼塊:如果類定義中包含有靜態(tài)代碼塊,那么在該階段JVM會(huì)執(zhí)行這些靜態(tài)代碼塊中的代碼。
  3. 調(diào)用類的初始化方法:在Java程序中,可以使用static關(guān)鍵字來(lái)定義一個(gè)類的靜態(tài)初始化方法(即static void methodName())。在該階段,JVM會(huì)調(diào)用這個(gè)類的靜態(tài)初始化方法。

類初始化的時(shí)機(jī)

類初始化時(shí)機(jī)包括以下四種情況:

  • 創(chuàng)建該類的實(shí)例對(duì)象時(shí),例如使用 new 關(guān)鍵字創(chuàng)建對(duì)象,類的初始化將被觸發(fā) 如果一個(gè)類是程序執(zhí)行的入口類(即包含 main() 方法的類),那么也會(huì)觸發(fā)該類的初始化操作。
  • 子類初始化會(huì)觸發(fā)父類初始化:當(dāng)一個(gè)子類被初始化時(shí),其父類也會(huì)被初始化。這意味著,如果一個(gè)類沒(méi)有被使用,那么它的父類也不會(huì)被初始化。
  • 當(dāng)調(diào)用類的靜態(tài)方法(不包括final方法和private方法)或訪問(wèn)類的靜態(tài)字段(不包括final字段)時(shí),類的初始化將被觸發(fā)。
  • 當(dāng)使用反射API對(duì)類進(jìn)行某些操作時(shí)(例如使用Class.forName()方法加載類、調(diào)用Class.newInstance()方法創(chuàng)建對(duì)象、調(diào)用Method.invoke()方法調(diào)用方法等),類的初始化將被觸發(fā)。

初始化是線程安全的JVM保證一個(gè)類的初始化只會(huì)由一個(gè)線程去執(zhí)行,其他線程需要等待該線程完成后才能訪問(wèn)該類。

下面用一個(gè)簡(jiǎn)單的Java代碼示例,展示JVM類加載機(jī)制中初始化階段的示例

public class MyClass {

    // 靜態(tài)變量
    public static String staticStr = "Hello, world!";

    static {
        System.out.println("MyClass is initialized.");
    }

    // 構(gòu)造方法
    public MyClass() {
        System.out.println("MyClass constructor is called.");
    }

    // 靜態(tài)方法
    public static void staticMethod() {
        System.out.println("MyClass staticMethod is called.");
    }
}

在上述代碼中,類MyClass包含一個(gè)靜態(tài)變量staticStr、一個(gè)靜態(tài)代碼塊和一個(gè)構(gòu)造方法,以及一個(gè)靜態(tài)方法staticMethod。當(dāng)程序首次使用MyClass類時(shí),JVM將會(huì)觸發(fā)MyClass類的初始化階段。可以通過(guò)下面的代碼來(lái)測(cè)試類的初始化:

public class Test {
    public static void main(String[] args) {
        System.out.println(MyClass.staticStr); // 調(diào)用靜態(tài)變量,觸發(fā)類初始化
        MyClass.staticMethod(); // 調(diào)用靜態(tài)方法,觸發(fā)類初始化
        MyClass obj = new MyClass(); // 創(chuàng)建對(duì)象,觸發(fā)類初始化
    }
}

在上面的代碼中,首先輸出了MyClass類的靜態(tài)變量staticStr,此時(shí)會(huì)觸發(fā)MyClass類的初始化;然后調(diào)用了靜態(tài)方法staticMethod,同樣會(huì)觸發(fā)MyClass類的初始化;最后創(chuàng)建了一個(gè)MyClass對(duì)象,也會(huì)觸發(fā)MyClass類的初始化。運(yùn)行上述代碼,可以看到以下輸出:

MyClass is initialized.
Hello, world!
MyClass staticMethod is called.
MyClass constructor is called.

輸出結(jié)果表明,MyClass類的初始化確實(shí)在首次使用該類時(shí)被觸發(fā),包括靜態(tài)變量、靜態(tài)代碼塊、靜態(tài)方法和構(gòu)造方法都被執(zhí)行了。

此外,如果一個(gè)類是另一個(gè)類的子類,那么在使用子類時(shí),父類也會(huì)被初始化。例如:

public class MyBaseClass {
    static {
        System.out.println("MyBaseClass is initialized.");
    }
}

public class MySubClass extends MyBaseClass {
    static {
        System.out.println("MySubClass is initialized.");
    }
}

public class Test {
    public static void main(String[] args) {
        MySubClass obj = new MySubClass(); // 創(chuàng)建子類對(duì)象,觸發(fā)父類和子類初始化
    }
}

在上述代碼中,當(dāng)創(chuàng)建MySubClass類的對(duì)象時(shí),將會(huì)觸發(fā)MyBaseClass和MySubClass類的初始化。運(yùn)行上述代碼,可以看到以下輸出:

MyBaseClass is initialized.
MySubClass is initialized.

總結(jié)

JVM的類加載機(jī)制采用了延遲加載的策略,即在需要使用類時(shí)才加載該類,這種方式可以提高程序的啟動(dòng)速度,也避免了不必要的資源浪費(fèi)。同時(shí),JVM還提供了多個(gè)類加載器,可以通過(guò)自定義類加載器實(shí)現(xiàn)特定的加載策略,例如動(dòng)態(tài)加載、遠(yuǎn)程加載等,從而滿足不同的應(yīng)用需求。

到此這篇關(guān)于聊一聊Java的JVM類加載機(jī)制的文章就介紹到這了,更多相關(guān)JVM類加載機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一個(gè)Servlet是如何處理多個(gè)請(qǐng)求的?

    一個(gè)Servlet是如何處理多個(gè)請(qǐng)求的?

    以前我一直以為一個(gè)Servlet只能處理一個(gè)請(qǐng)求,后來(lái)發(fā)現(xiàn)是自己太菜了,可以借助攜帶一個(gè)參數(shù)來(lái)完成多個(gè)請(qǐng)求的處理,根據(jù)參數(shù)的不同,在核心的service方法中調(diào)用不同的業(yè)務(wù)方法,來(lái)實(shí)現(xiàn)處理多個(gè)servlet請(qǐng)求的目的,廢話不多說(shuō),直接上代碼,需要的朋友可以參考下
    2021-06-06
  • Java二叉樹(shù)的遍歷思想及核心代碼實(shí)現(xiàn)

    Java二叉樹(shù)的遍歷思想及核心代碼實(shí)現(xiàn)

    今天小編就為大家分享一篇關(guān)于Java二叉樹(shù)的遍歷思想及核心代碼實(shí)現(xiàn),小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • mybatis整合springboot報(bào)BindingException:Invalid?bound?statement?(not?found)異常解決

    mybatis整合springboot報(bào)BindingException:Invalid?bound?stateme

    這篇文章主要給大家介紹了關(guān)于mybatis整合springboot報(bào)BindingException:Invalid?bound?statement?(not?found)異常的解決辦法,這個(gè)錯(cuò)誤通常是由于Mapper文件中的statement?id與Java代碼中的方法名不一致導(dǎo)致的,需要的朋友可以參考下
    2024-01-01
  • spring-mvc/springboot使用MockMvc對(duì)controller進(jìn)行測(cè)試

    spring-mvc/springboot使用MockMvc對(duì)controller進(jìn)行測(cè)試

    這篇文章主要介紹了spring-mvc/springboot使用MockMvc對(duì)controller進(jìn)行測(cè)試,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • springboot發(fā)布dubbo服務(wù)注冊(cè)到nacos實(shí)現(xiàn)方式

    springboot發(fā)布dubbo服務(wù)注冊(cè)到nacos實(shí)現(xiàn)方式

    這篇文章主要介紹了springboot發(fā)布dubbo服務(wù)注冊(cè)到nacos實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Mybatis Mapper XML文件-插入,更新,刪除詳解(insert, update and delete)

    Mybatis Mapper XML文件-插入,更新,刪除詳解(insert, updat

    這篇文章主要介紹了MyBatis的Mapper XML文件中用于插入、更新和刪除數(shù)據(jù)的語(yǔ)句,包括這些語(yǔ)句的屬性和子元素的使用方法
    2025-02-02
  • Spring使用@responseBody與序列化詳解

    Spring使用@responseBody與序列化詳解

    這篇文章主要介紹了Spring使用@responseBody與序列化詳解,@responseBody注解的作用是將controller的方法返回的對(duì)象通過(guò)適當(dāng)?shù)霓D(zhuǎn)換器轉(zhuǎn)換為指定的格式之后,寫(xiě)入到response對(duì)象的body區(qū),通常用來(lái)返回JSON數(shù)據(jù)或者是XML數(shù)據(jù),需要的朋友可以參考下
    2023-08-08
  • java如何利用poi解析doc和docx中的數(shù)據(jù)

    java如何利用poi解析doc和docx中的數(shù)據(jù)

    這篇文章主要給大家介紹了關(guān)于java如何利用poi解析doc和docx中數(shù)據(jù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • java并發(fā)編程synchronized底層實(shí)現(xiàn)原理

    java并發(fā)編程synchronized底層實(shí)現(xiàn)原理

    這篇文章主要介紹了java并發(fā)編程synchronized底層實(shí)現(xiàn)原理
    2022-02-02
  • RabbitMQ實(shí)現(xiàn)消息可靠性傳遞過(guò)程講解

    RabbitMQ實(shí)現(xiàn)消息可靠性傳遞過(guò)程講解

    消息的可靠性傳遞是指保證消息百分百發(fā)送到消息隊(duì)列中去,這篇文章主要介紹了RabbitMQ實(shí)現(xiàn)消息可靠性傳遞過(guò)程,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05

最新評(píng)論

桃源县| 金门县| 调兵山市| 合山市| 汶川县| 辰溪县| 咸阳市| 东乌| 孟州市| 肃北| 隆德县| 沂南县| 乾安县| 那坡县| 兰考县| 买车| 浠水县| 宣威市| 黄大仙区| 博罗县| 大港区| 满洲里市| 东山县| 铜鼓县| 双桥区| 神农架林区| 双峰县| 道孚县| 榆树市| 和平县| 双流县| 广昌县| 会宁县| 牟定县| 永城市| 福泉市| 佛山市| 时尚| 兴义市| 青铜峡市| 万山特区|