亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文帶你搞懂Java類(lèi)加載機(jī)制

 更新時(shí)間:2023年08月15日 08:36:34   作者:蜀山劍客李沐白  
Java?類(lèi)加載機(jī)制是?Java?運(yùn)行時(shí)的核心組成部分,負(fù)責(zé)在程序運(yùn)行過(guò)程中動(dòng)態(tài)加載和連接類(lèi)文件,并將其轉(zhuǎn)換為可執(zhí)行代碼,接下來(lái)小編就來(lái)帶大家搞懂面試官老問(wèn)的?Java?類(lèi)加載機(jī)制,需要的朋友可以參考下

一、介紹

Java 類(lèi)加載機(jī)制的作用和重要性

Java 類(lèi)加載機(jī)制是 Java 運(yùn)行時(shí)的核心組成部分,負(fù)責(zé)在程序運(yùn)行過(guò)程中動(dòng)態(tài)加載和連接類(lèi)文件,并將其轉(zhuǎn)換為可執(zhí)行代碼。

  • 實(shí)現(xiàn)動(dòng)態(tài)加載:Java 類(lèi)加載機(jī)制允許程序在運(yùn)行時(shí)根據(jù)需要?jiǎng)討B(tài)地加載類(lèi)文件。這種能力使得開(kāi)發(fā)人員可以根據(jù)實(shí)際需求來(lái)加載所需的類(lèi),而不需要一次性加載所有的類(lèi)。這對(duì)于大型應(yīng)用程序和框架來(lái)說(shuō)特別有用,因?yàn)樗鼈兛赡馨罅康念?lèi),但只有在需要時(shí)才會(huì)加載。

  • 解決依賴(lài)關(guān)系:Java 類(lèi)加載機(jī)制可以解決類(lèi)之間的依賴(lài)關(guān)系。當(dāng)一個(gè)類(lèi)引用另一個(gè)類(lèi)時(shí),如果被引用的類(lèi)還未被加載,類(lèi)加載機(jī)制會(huì)自動(dòng)觸發(fā)對(duì)被引用類(lèi)的加載。這種機(jī)制確保了類(lèi)的正確順序加載,避免了由于依賴(lài)關(guān)系引起的編譯錯(cuò)誤或運(yùn)行時(shí)錯(cuò)誤。

  • 實(shí)現(xiàn)類(lèi)的隔離性:Java 類(lèi)加載器通過(guò)不同的命名空間實(shí)現(xiàn)了類(lèi)的隔離性。每個(gè)類(lèi)加載器都有自己的命名空間,同一個(gè)類(lèi)可以被不同的類(lèi)加載器加載多次,每次都會(huì)生成獨(dú)立的類(lèi)對(duì)象。這種隔離性使得不同的模塊或應(yīng)用可以使用不同的類(lèi)版本,避免了類(lèi)之間的沖突。

  • 支持動(dòng)態(tài)代理和反射:Java 類(lèi)加載機(jī)制為動(dòng)態(tài)代理和反射提供了基礎(chǔ)。通過(guò)類(lèi)加載器,我們可以在運(yùn)行時(shí)動(dòng)態(tài)地生成代理類(lèi),并且可以在運(yùn)行時(shí)獲取和操作類(lèi)的字段、方法等信息。這種能力使得 Java 在面向?qū)ο缶幊毯涂蚣茉O(shè)計(jì)方面更加靈活和強(qiáng)大。

  • 實(shí)現(xiàn)安全性和權(quán)限控制:Java 類(lèi)加載機(jī)制可以實(shí)現(xiàn)安全性和權(quán)限控制。它可以限制某些類(lèi)只能由特定的類(lèi)加載器加載,從而控制類(lèi)的訪問(wèn)權(quán)限。這對(duì)于保護(hù)系統(tǒng)的安全性和防止惡意代碼的執(zhí)行至關(guān)重要。

二、類(lèi)加載器

加載器類(lèi)別

啟動(dòng)類(lèi)加載器(Bootstrap Class Loader)

啟動(dòng)類(lèi)加載器(Bootstrap Class Loader)是 Java 類(lèi)加載器中的最頂層的一個(gè)加載器,它負(fù)責(zé)加載 Java 運(yùn)行時(shí)核心類(lèi)庫(kù)和其他被 JVM 所信任的重要類(lèi)。

  • 加載核心類(lèi)庫(kù):?jiǎn)?dòng)類(lèi)加載器負(fù)責(zé)加載 Java 運(yùn)行時(shí)所需的核心類(lèi)庫(kù),包括Java標(biāo)準(zhǔn)庫(kù)(rt.jar)和擴(kuò)展庫(kù)(ext目錄下的jar文件)。這些類(lèi)庫(kù)包含了 Java 語(yǔ)言的基本類(lèi),如Object、String等,以及Java運(yùn)行時(shí)的核心類(lèi),如Class、ClassLoader等。

  • 無(wú)法直接獲?。?jiǎn)?dòng)類(lèi)加載器是 JVM 實(shí)現(xiàn)的一部分,通常由系統(tǒng)或者虛擬機(jī)實(shí)現(xiàn)語(yǔ)言編寫(xiě),無(wú)法在Java代碼中直接獲取到。它是 JVM 的一部分,存在于JVM內(nèi)核中。

  • 實(shí)現(xiàn)為本地代碼:由于啟動(dòng)類(lèi)加載器是 JVM 實(shí)現(xiàn)的一部分,因此它的實(shí)現(xiàn)通常是用本地代碼(C/C++)編寫(xiě)的。這樣可以保證加載器的安全性和效率。

  • 非Java類(lèi)加載器:?jiǎn)?dòng)類(lèi)加載器不是一個(gè)普通的Java類(lèi)加載器,它不繼承自java.lang.ClassLoader類(lèi)(Java中所有類(lèi)加載器的基類(lèi)),而是由JVM實(shí)現(xiàn)為特殊的邏輯加載器。

  • 獨(dú)立于Java應(yīng)用:?jiǎn)?dòng)類(lèi)加載器是在 JVM 啟動(dòng)過(guò)程中被創(chuàng)建的,它獨(dú)立于任何Java應(yīng)用程序。它的主要目的是加載核心類(lèi)庫(kù),為后續(xù)的類(lèi)加載器提供基礎(chǔ)。

  • 位于引導(dǎo)類(lèi)路徑上:?jiǎn)?dòng)類(lèi)加載器從一個(gè)特定的位置加載類(lèi),該位置被稱(chēng)為引導(dǎo)類(lèi)路徑(Bootstrap Classpath)。引導(dǎo)類(lèi)路徑通常是 JVM 實(shí)現(xiàn)的一部分,并且會(huì)根據(jù)不同的 JVM 實(shí)現(xiàn)而有所不同。

  • 無(wú)法自定義:由于啟動(dòng)類(lèi)加載器是 JVM 的一部分,因此無(wú)法對(duì)其進(jìn)行自定義或替換。它負(fù)責(zé)加載 Java 運(yùn)行時(shí)的基礎(chǔ)類(lèi)庫(kù),保證了Java程序運(yùn)行的穩(wěn)定性和安全性。

擴(kuò)展類(lèi)加載器(Extension Class Loader)

擴(kuò)展類(lèi)加載器(Extension Class Loader)是 Java 類(lèi)加載器中的一種,它是屬于標(biāo)準(zhǔn)的系統(tǒng)類(lèi)加載器的一部分。擴(kuò)展類(lèi)加載器用于加載 Java 虛擬機(jī)擴(kuò)展目錄(Java Extension Directory)中的類(lèi)庫(kù)。

  • 加載擴(kuò)展目錄:擴(kuò)展類(lèi)加載器負(fù)責(zé)加載 Java 虛擬機(jī)的擴(kuò)展目錄(Java Extension Directory),該目錄的位置由系統(tǒng)屬性 java.ext.dirs 指定。默認(rèn)情況下,擴(kuò)展目錄位于 <JRE_HOME>/lib/ext 目錄下。

  • 擴(kuò)展目錄的作用:擴(kuò)展目錄是用于存放 Java 虛擬機(jī)的擴(kuò)展類(lèi)庫(kù)或第三方庫(kù)的目錄。它提供了一種在 Java 平臺(tái)上安裝額外功能的機(jī)制,使得開(kāi)發(fā)人員可以通過(guò)簡(jiǎn)單地將 JAR 文件放置到擴(kuò)展目錄中來(lái)擴(kuò)展 Java 的功能。

  • 從父類(lèi)加載器繼承:擴(kuò)展類(lèi)加載器是標(biāo)準(zhǔn)的系統(tǒng)類(lèi)加載器的一個(gè)實(shí)例,它從父類(lèi)加載器(一般是啟動(dòng)類(lèi)加載器)繼承加載類(lèi)的能力。這意味著當(dāng)擴(kuò)展類(lèi)加載器無(wú)法加載一個(gè)類(lèi)時(shí),它會(huì)委派給父類(lèi)加載器來(lái)嘗試加載。

  • 加載擴(kuò)展類(lèi)庫(kù):擴(kuò)展類(lèi)加載器主要用于加載擴(kuò)展目錄中的類(lèi)庫(kù)。擴(kuò)展目錄中的類(lèi)庫(kù)是一些提供額外功能或擴(kuò)展 Java API 的類(lèi)庫(kù),它們通常以 JAR 文件的形式存在。

  • 獨(dú)立于應(yīng)用程序:擴(kuò)展類(lèi)加載器是獨(dú)立于應(yīng)用程序的,它是 JVM 內(nèi)置的一個(gè)類(lèi)加載器,負(fù)責(zé)加載系統(tǒng)級(jí)別的類(lèi)庫(kù)。它和應(yīng)用程序的類(lèi)加載器(如應(yīng)用類(lèi)加載器)是相互獨(dú)立的。

  • 可以自定義擴(kuò)展目錄:通過(guò)修改系統(tǒng)屬性 java.ext.dirs,我們可以自定義擴(kuò)展目錄的位置。這樣,我們可以將一些額外的類(lèi)庫(kù)放置到自定義的擴(kuò)展目錄中,并由擴(kuò)展類(lèi)加載器加載。

  • 實(shí)現(xiàn)為純Java類(lèi):擴(kuò)展類(lèi)加載器的實(shí)現(xiàn)是一個(gè)普通的 Java 類(lèi),它繼承自 java.net.URLClassLoader。這使得我們可以通過(guò) Java 代碼來(lái)獲取擴(kuò)展類(lèi)加載器實(shí)例,并與其交互。

應(yīng)用程序類(lèi)加載器(Application Class Loader)

應(yīng)用程序類(lèi)加載器(Application Class Loader),也稱(chēng)為系統(tǒng)類(lèi)加載器(System Class Loader),是 Java 類(lèi)加載器中的一種。它負(fù)責(zé)加載應(yīng)用程序的類(lèi)和資源文件。

  • 加載應(yīng)用程序類(lèi):應(yīng)用程序類(lèi)加載器是負(fù)責(zé)加載應(yīng)用程序的類(lèi)的主要類(lèi)加載器。它從指定的類(lèi)路徑(Classpath)中加載類(lèi)文件,包括應(yīng)用程序的源代碼編譯后生成的字節(jié)碼文件。

  • 類(lèi)路徑的設(shè)置:類(lèi)路徑是指用于查找類(lèi)文件的路徑列表。在運(yùn)行 Java 程序時(shí),我們可以通過(guò)命令行參數(shù) -classpath 或簡(jiǎn)寫(xiě)的 -cp 來(lái)設(shè)置類(lèi)路徑。類(lèi)路徑可以包含目錄和 JAR 文件。

  • 與系統(tǒng)類(lèi)加載器關(guān)聯(lián):應(yīng)用程序類(lèi)加載器是系統(tǒng)類(lèi)加載器的實(shí)例,它繼承了系統(tǒng)類(lèi)加載器的行為和能力。系統(tǒng)類(lèi)加載器是ClassLoader類(lèi)的子類(lèi),Java虛擬機(jī)在啟動(dòng)時(shí)自動(dòng)創(chuàng)建了一個(gè)系統(tǒng)類(lèi)加載器,并將其指定給應(yīng)用程序類(lèi)加載器。

  • 搜索順序:應(yīng)用程序類(lèi)加載器按照特定的搜索順序加載類(lèi)。首先,它會(huì)嘗試使用自己的類(lèi)路徑加載類(lèi)文件。如果找不到,則會(huì)委派給父類(lèi)加載器,依次往上搜索,直到達(dá)到頂層的啟動(dòng)類(lèi)加載器為止。這種委派模型稱(chēng)為雙親委派模型。

  • 加載應(yīng)用程序資源:除了加載類(lèi)文件,應(yīng)用程序類(lèi)加載器還負(fù)責(zé)加載應(yīng)用程序的資源文件。資源文件可以是文本文件、配置文件、圖片等應(yīng)用程序所需的其他非類(lèi)文件。通過(guò)應(yīng)用程序類(lèi)加載器,我們可以使用 getResource()getResourceAsStream() 方法來(lái)獲取應(yīng)用程序的資源。

  • 可以自定義類(lèi)加載器:雖然應(yīng)用程序類(lèi)加載器是由Java虛擬機(jī)在運(yùn)行時(shí)自動(dòng)創(chuàng)建的,但我們也可以通過(guò)編寫(xiě)自定義的類(lèi)加載器來(lái)替換或擴(kuò)展它的功能。自定義類(lèi)加載器可以用于實(shí)現(xiàn)特定的類(lèi)加載策略,如從數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)或非標(biāo)準(zhǔn)路徑加載類(lèi)。

  • 獨(dú)立于應(yīng)用程序:應(yīng)用程序類(lèi)加載器是與特定的應(yīng)用程序相關(guān)聯(lián)的,它負(fù)責(zé)加載應(yīng)用程序的類(lèi)和資源。每個(gè)應(yīng)用程序都有自己獨(dú)立的應(yīng)用程序類(lèi)加載器,不同的應(yīng)用程序之間相互獨(dú)立。

雙親委派模型(Delegation Model)

雙親委派模型(Parent Delegation Model)是 Java 類(lèi)加載器的一種工作機(jī)制,它定義了類(lèi)加載器之間的層次關(guān)系和類(lèi)加載的優(yōu)先級(jí)。

  • 類(lèi)加載器層次結(jié)構(gòu):在 Java 類(lèi)加載器中,存在一個(gè)層次結(jié)構(gòu),由多個(gè)類(lèi)加載器按照特定的順序組成。這個(gè)層次結(jié)構(gòu)通常被稱(chēng)為類(lèi)加載器鏈。

  • 父子關(guān)系:雙親委派模型中,每個(gè)類(lèi)加載器都有一個(gè)父類(lèi)加載器(除了根類(lèi)加載器),它們之間通過(guò)組合關(guān)系建立起層次結(jié)構(gòu)。一個(gè)類(lèi)加載器的父加載器通常是其上一級(jí)的加載器。

  • 加載優(yōu)先級(jí):當(dāng)一個(gè)類(lèi)加載器需要加載一個(gè)類(lèi)時(shí),它首先將加載請(qǐng)求委派給其父類(lèi)加載器。如果父加載器能夠加載該類(lèi),那么就直接返回該類(lèi);否則,才由子加載器嘗試加載。這樣一層一層的委派下去,直到父加載器無(wú)法加載或者到達(dá)最頂層的啟動(dòng)類(lèi)加載器。

  • 避免重復(fù)加載:雙親委派模型的核心思想是避免重復(fù)加載類(lèi)。在加載過(guò)程中,如果某個(gè)類(lèi)已經(jīng)由父類(lèi)加載器加載過(guò)了,那么子類(lèi)加載器就不再加載,直接使用父加載器已加載的版本。這樣能夠確保同一個(gè)類(lèi)在內(nèi)存中只有一份,避免了類(lèi)的重復(fù)定義和沖突。

  • 安全性保證:雙親委派模型也提供了一定的安全性保證。通過(guò)設(shè)置不同的類(lèi)加載器層次結(jié)構(gòu),可以控制類(lèi)加載的權(quán)限。核心的 Java API 類(lèi)庫(kù)通常由啟動(dòng)類(lèi)加載器加載,而應(yīng)用程序自定義的類(lèi)則由應(yīng)用程序類(lèi)加載器加載。這樣,核心類(lèi)庫(kù)的類(lèi)無(wú)法被重新定義或篡改,保障了Java平臺(tái)的穩(wěn)定和安全。

  • 自定義類(lèi)加載器:雙親委派模型也為自定義類(lèi)加載器提供了基礎(chǔ)。通過(guò)繼承 ClassLoader 類(lèi)并重寫(xiě)其方法,我們可以自定義類(lèi)加載器,實(shí)現(xiàn)特定的類(lèi)加載策略。自定義類(lèi)加載器可以在加載類(lèi)的過(guò)程中修改默認(rèn)的委派行為,實(shí)現(xiàn)一些特殊需求。

雙親委派模型是 Java 類(lèi)加載器的一種工作機(jī)制,定義了類(lèi)加載器之間的層次關(guān)系和類(lèi)加載的優(yōu)先級(jí)。它通過(guò)委派機(jī)制,使得父加載器先嘗試加載類(lèi),避免了重復(fù)加載和類(lèi)的沖突。雙親委派模型也提供了一定的安全性保證,控制了類(lèi)加載的權(quán)限。同時(shí),雙親委派模型也為自定義類(lèi)加載器提供了基礎(chǔ),可以實(shí)現(xiàn)特定的類(lèi)加載策略。

自定義類(lèi)加載器

自定義類(lèi)加載器是通過(guò)繼承ClassLoader類(lèi)來(lái)實(shí)現(xiàn)的。ClassLoader是Java虛擬機(jī)提供的用于加載類(lèi)和資源的基礎(chǔ)類(lèi)加載器,自定義類(lèi)加載器可以在其基礎(chǔ)上實(shí)現(xiàn)特定的加載策略。

  • 繼承ClassLoader類(lèi):創(chuàng)建一個(gè)自定義類(lèi)加載器需要定義一個(gè)類(lèi),并繼承ClassLoader類(lèi)。
public class CustomClassLoader extends ClassLoader {
    // 自定義類(lèi)加載器的實(shí)現(xiàn)
}
  • 重寫(xiě)findClass()方法:在自定義類(lèi)加載器中,需要重寫(xiě)findClass(String name)方法。這個(gè)方法負(fù)責(zé)根據(jù)類(lèi)的名稱(chēng)查找并加載類(lèi)的字節(jié)碼。
public class CustomClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] byteCode = loadClassBytes(name); // 加載類(lèi)的字節(jié)碼
        if (byteCode == null) {
            throw new ClassNotFoundException();
        }
        return defineClass(name, byteCode, 0, byteCode.length);
    }
    private byte[] loadClassBytes(String name) {
        // 根據(jù)name加載類(lèi)的字節(jié)碼,可從文件系統(tǒng)、網(wǎng)絡(luò)等位置加載
        // 返回字節(jié)碼的字節(jié)數(shù)組
    }
}
  • 加載類(lèi)的字節(jié)碼:在findClass()方法中,我們需要根據(jù)類(lèi)的名稱(chēng)加載相應(yīng)的字節(jié)碼。這一步可以根據(jù)需求自由實(shí)現(xiàn),例如從文件系統(tǒng)、網(wǎng)絡(luò)或其他非標(biāo)準(zhǔn)位置加載。
private byte[] loadClassBytes(String name) {
    // 根據(jù)name加載類(lèi)的字節(jié)碼,可從文件系統(tǒng)、網(wǎng)絡(luò)等位置加載
    // 返回字節(jié)碼的字節(jié)數(shù)組
    try (InputStream inputStream = new FileInputStream(name + ".class")) {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            byteStream.write(buffer, 0, bytesRead);
        }
        return byteStream.toByteArray();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

這個(gè)示例中,我們通過(guò)從文件系統(tǒng)加載類(lèi)的字節(jié)碼。你可以根據(jù)實(shí)際需求自行實(shí)現(xiàn),例如從網(wǎng)絡(luò)下載字節(jié)碼或從其他自定義位置加載。

  • 使用自定義類(lèi)加載器:完成自定義類(lèi)加載器的實(shí)現(xiàn)后,我們可以使用它來(lái)加載自己定義的類(lèi)。
public class Main {
    public static void main(String[] args) {
        CustomClassLoader classLoader = new CustomClassLoader();
        try {
            Class<?> customClass = classLoader.loadClass("com.example.CustomClass");
            // 使用加載的類(lèi)進(jìn)行操作
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

在這個(gè)示例中,我們創(chuàng)建了一個(gè)CustomClassLoader實(shí)例,并調(diào)用loadClass()方法加載指定的類(lèi)。返回的Class對(duì)象可以用于實(shí)例化對(duì)象或調(diào)用類(lèi)的靜態(tài)方法。

  • 類(lèi)加載器命名空間:自定義類(lèi)加載器還可以實(shí)現(xiàn)類(lèi)加載器命名空間的隔離。這樣,不同的類(lèi)加載器加載的類(lèi)相互隔離,避免類(lèi)的沖突。
public class CustomClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        if (shouldLoadWithCustomClassLoader(name)) {
            byte[] byteCode = loadClassBytes(name);
            if (byteCode == null) {
                throw new ClassNotFoundException();
            }
            return defineClass(name, byteCode, 0, byteCode.length);
        } else {
            return super.findClass(name);
        }
    }
    private boolean shouldLoadWithCustomClassLoader(String name) {
        // 根據(jù)自定義規(guī)則判斷是否由自定義類(lèi)加載器加載
        // 返回true表示由自定義類(lèi)加載器加載,返回false表示由父類(lèi)加載器加載
    }
}

在這個(gè)示例中,我們通過(guò)重寫(xiě)findClass()方法,根據(jù)自定義規(guī)則判斷是否應(yīng)該由自定義類(lèi)加載器加載類(lèi)。如果滿(mǎn)足條件,則調(diào)用defineClass()方法加載類(lèi)的字節(jié)碼;否則,則交給父類(lèi)加載器處理。

三、類(lèi)加載過(guò)程

加載階段(Loading)

  • 查找并加載類(lèi)的字節(jié)碼文件:Java虛擬機(jī)根據(jù)類(lèi)的全限定名在文件系統(tǒng)、網(wǎng)絡(luò)或其他來(lái)源中查找并讀取類(lèi)的字節(jié)碼文件。字節(jié)碼文件通常以.class文件形式存在。
  • 創(chuàng)建對(duì)應(yīng)的Class對(duì)象:一旦字節(jié)碼文件被獲取,Java虛擬機(jī)會(huì)將其轉(zhuǎn)化為一個(gè)Class對(duì)象。這個(gè)Class對(duì)象包含了類(lèi)的結(jié)構(gòu)信息,并用于在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建對(duì)象。

驗(yàn)證階段(Verification)

  • 文件格式驗(yàn)證:Java虛擬機(jī)對(duì)字節(jié)碼文件的格式進(jìn)行驗(yàn)證,確保它符合Java虛擬機(jī)規(guī)范定義的文件格式要求。
  • 字節(jié)碼驗(yàn)證:驗(yàn)證字節(jié)碼的邏輯合法性,避免潛在的類(lèi)型安全問(wèn)題。
  • 符號(hào)引用驗(yàn)證:對(duì)類(lèi)中的符號(hào)引用進(jìn)行驗(yàn)證,確保引用的目標(biāo)是有效的。
  • 內(nèi)部一致性驗(yàn)證:驗(yàn)證類(lèi)的內(nèi)部結(jié)構(gòu)是否一致,比如父類(lèi)與子類(lèi)之間的繼承關(guān)系是否正確。

準(zhǔn)備階段(Preparation)

  • 為靜態(tài)變量分配內(nèi)存空間:Java虛擬機(jī)為類(lèi)的靜態(tài)變量在內(nèi)存中分配空間,這些變量被存儲(chǔ)在方法區(qū)中。
  • 設(shè)置默認(rèn)初始值:靜態(tài)變量被初始化為默認(rèn)值,比如整數(shù)類(lèi)型變量初始化為0,引用類(lèi)型變量初始化為null。

解析階段(Resolution)

  • 符號(hào)引用轉(zhuǎn)換為直接引用:Java虛擬機(jī)將符號(hào)引用轉(zhuǎn)換為直接引用,以便后續(xù)使用。
  • 類(lèi)、接口、字段和方法解析:將符號(hào)引用解析為對(duì)應(yīng)的類(lèi)、接口、字段和方法的直接引用,以便進(jìn)一步操作。

初始化階段(Initialization)

  • 執(zhí)行靜態(tài)變量賦值和靜態(tài)代碼塊:Java虛擬機(jī)執(zhí)行類(lèi)的初始化代碼,給靜態(tài)變量賦予初始值,并執(zhí)行靜態(tài)代碼塊中的代碼。這些代碼通常用于完成靜態(tài)變量的初始化以及其他一次性的初始化工作。

使用階段(Usage)

  • 創(chuàng)建實(shí)例對(duì)象:在類(lèi)加載完成后,可以通過(guò)構(gòu)造函數(shù)創(chuàng)建類(lèi)的實(shí)例對(duì)象。
  • 調(diào)用方法:通過(guò)對(duì)象調(diào)用類(lèi)的方法。
  • 訪問(wèn)字段:通過(guò)對(duì)象訪問(wèn)類(lèi)的字段(成員變量)。

四、類(lèi)的卸載

垃圾回收對(duì)類(lèi)的卸載處理

在Java虛擬機(jī)中,垃圾回收(Garbage Collection)是負(fù)責(zé)自動(dòng)回收不再使用的內(nèi)存資源的機(jī)制。當(dāng)一個(gè)類(lèi)不再被使用時(shí),Java虛擬機(jī)會(huì)通過(guò)垃圾回收來(lái)回收該類(lèi)所占用的內(nèi)存空間,并對(duì)其進(jìn)行卸載處理。

垃圾回收器通過(guò)標(biāo)記-清除(Mark and Sweep)算法或其他相關(guān)算法來(lái)識(shí)別和回收無(wú)用的對(duì)象。當(dāng)垃圾回收器確定某個(gè)類(lèi)的所有實(shí)例對(duì)象都已經(jīng)不再被引用時(shí),它可以判斷該類(lèi)已經(jīng)不再需要存在于內(nèi)存中。

在垃圾回收過(guò)程中,如果一個(gè)類(lèi)的所有實(shí)例對(duì)象都被回收,那么虛擬機(jī)將執(zhí)行類(lèi)的卸載操作。類(lèi)卸載的具體過(guò)程如下:

  • 首先,虛擬機(jī)將檢查該類(lèi)的所有實(shí)例對(duì)象是否都已經(jīng)被回收。這可以通過(guò)遍歷堆內(nèi)存中的對(duì)象來(lái)完成。
  • 如果虛擬機(jī)確認(rèn)該類(lèi)的所有實(shí)例對(duì)象都已經(jīng)被回收,那么它將進(jìn)一步檢查該類(lèi)的類(lèi)加載器是否也已經(jīng)不再被引用。
  • 如果類(lèi)加載器也不再被引用,那么虛擬機(jī)就可以卸載該類(lèi)。卸載操作會(huì)釋放該類(lèi)所占用的內(nèi)存空間,并且將該類(lèi)在方法區(qū)中的相關(guān)信息清除。

需要注意的是,類(lèi)的卸載是一個(gè)相對(duì)較為復(fù)雜的操作,且其具體實(shí)現(xiàn)可能因Java虛擬機(jī)的不同而有所差異。一般情況下,只有當(dāng)滿(mǎn)足特定條件時(shí),垃圾回收器才會(huì)觸發(fā)類(lèi)的卸載操作,例如類(lèi)的所有實(shí)例對(duì)象都已經(jīng)被回收,并且該類(lèi)的類(lèi)加載器也不再被引用。

卸載條件和判定過(guò)程

類(lèi)的卸載是一個(gè)相對(duì)較為復(fù)雜的操作,其觸發(fā)和判定過(guò)程可能因Java虛擬機(jī)的不同而有所差異。一般情況下,以下條件之一滿(mǎn)足時(shí),垃圾回收器才會(huì)觸發(fā)類(lèi)的卸載操作:

  • 該類(lèi)的所有實(shí)例對(duì)象都已經(jīng)被回收。
  • 該類(lèi)的類(lèi)加載器已經(jīng)不再被引用。

卸載判定過(guò)程:

在Java虛擬機(jī)中,類(lèi)的卸載判定通常是由垃圾回收器來(lái)完成的。具體的卸載判定過(guò)程可能因虛擬機(jī)的實(shí)現(xiàn)而有所不同,但一般會(huì)包括以下步驟:

  • 根據(jù)特定的條件觸發(fā)垃圾回收:當(dāng)滿(mǎn)足一定的條件時(shí),虛擬機(jī)會(huì)觸發(fā)垃圾回收。這些條件可以是虛擬機(jī)自身設(shè)定的策略,或者通過(guò)用戶(hù)設(shè)置的參數(shù)進(jìn)行配置。

  • 標(biāo)記階段:垃圾回收器會(huì)對(duì)堆內(nèi)存中的對(duì)象進(jìn)行標(biāo)記,以識(shí)別哪些對(duì)象是可達(dá)的,哪些對(duì)象是不可達(dá)的??蛇_(dá)對(duì)象通常意味著它們?nèi)匀槐灰茫豢蛇_(dá)對(duì)象則表示它們已經(jīng)沒(méi)有與之關(guān)聯(lián)的引用。

  • 清除階段:在標(biāo)記階段之后,垃圾回收器會(huì)清除那些被標(biāo)記為不可達(dá)的對(duì)象。這樣一來(lái),堆內(nèi)存中就會(huì)釋放出那些不再被引用的對(duì)象所占用的空間。

  • 類(lèi)的卸載判定:在清除階段之后,垃圾回收器會(huì)進(jìn)一步檢查類(lèi)的卸載條件。它會(huì)遍歷已加載的類(lèi),并檢查每個(gè)類(lèi)的實(shí)例對(duì)象是否都已經(jīng)被回收。如果一個(gè)類(lèi)的所有實(shí)例對(duì)象都已經(jīng)被回收,那么虛擬機(jī)會(huì)繼續(xù)檢查該類(lèi)的類(lèi)加載器是否還被引用。

  • 卸載操作:如果一個(gè)類(lèi)的所有實(shí)例對(duì)象都已經(jīng)被回收,并且該類(lèi)的類(lèi)加載器也不再被引用,那么虛擬機(jī)可以執(zhí)行類(lèi)的卸載操作。卸載操作將釋放該類(lèi)所占用的內(nèi)存空間,并且將該類(lèi)在方法區(qū)中的相關(guān)信息清除。

需要注意的是,垃圾回收和類(lèi)的卸載通常是由虛擬機(jī)自動(dòng)進(jìn)行的,我們不需要顯式地觸發(fā)或管理類(lèi)的卸載過(guò)程。這種自動(dòng)化的內(nèi)存管理機(jī)制確保了Java程序的運(yùn)行效率和穩(wěn)定性。

五、類(lèi)加載機(jī)制的應(yīng)用場(chǎng)景

  • 動(dòng)態(tài)類(lèi)加載和使用:類(lèi)加載機(jī)制允許在運(yùn)行時(shí)動(dòng)態(tài)地加載和使用類(lèi)。這對(duì)于實(shí)現(xiàn)插件化、模塊化和動(dòng)態(tài)擴(kuò)展的應(yīng)用非常有用。例如,Java中的反射機(jī)制就依賴(lài)于類(lèi)加載機(jī)制,通過(guò)加載和使用未知類(lèi)的信息,實(shí)現(xiàn)了動(dòng)態(tài)調(diào)用和綁定。

  • 自定義類(lèi)加載器:Java提供了自定義類(lèi)加載器的能力,開(kāi)發(fā)人員可以根據(jù)特定需求實(shí)現(xiàn)自定義的類(lèi)加載器,從而加載非標(biāo)準(zhǔn)位置或非標(biāo)準(zhǔn)格式的類(lèi)文件。這在一些特殊場(chǎng)景下很有用,比如熱部署、代碼隔離和安全性管理。

  • 動(dòng)態(tài)代理和AOP(面向切面編程):類(lèi)加載機(jī)制可以通過(guò)動(dòng)態(tài)代理生成代理類(lèi),實(shí)現(xiàn)日志記錄、事務(wù)管理等橫切邏輯的切面編程。通過(guò)在類(lèi)加載過(guò)程中對(duì)字節(jié)碼進(jìn)行增強(qiáng),可以在運(yùn)行時(shí)動(dòng)態(tài)地為類(lèi)添加額外的功能。

  • 類(lèi)的隔離和沙箱環(huán)境:類(lèi)加載機(jī)制對(duì)類(lèi)的加載、訪問(wèn)和使用進(jìn)行了嚴(yán)格的控制,可以實(shí)現(xiàn)類(lèi)的隔離和沙箱環(huán)境。這在安全性要求較高的環(huán)境中非常重要,比如瀏覽器插件、操作系統(tǒng)級(jí)別的應(yīng)用程序和網(wǎng)絡(luò)服務(wù)器。

  • 類(lèi)加載器鏈和模塊化:類(lèi)加載機(jī)制通過(guò)類(lèi)加載器鏈的方式,實(shí)現(xiàn)了類(lèi)的層次化加載和命名空間的劃分,促進(jìn)了模塊化開(kāi)發(fā)和組件化架構(gòu)。比如Java的模塊化系統(tǒng)——Java Platform Module System(JPMS),依賴(lài)于類(lèi)加載機(jī)制來(lái)加載和管理模塊。

  • 運(yùn)行時(shí)類(lèi)型信息(RTTI):類(lèi)加載機(jī)制提供了運(yùn)行時(shí)類(lèi)型信息的支持,包括獲取類(lèi)的名稱(chēng)、方法、字段等元數(shù)據(jù)信息,以及進(jìn)行類(lèi)型檢查和轉(zhuǎn)換。這對(duì)于動(dòng)態(tài)編程和反射等場(chǎng)景非常有用。

以上就是一文帶你搞懂Java類(lèi)加載機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于Java類(lèi)加載機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Javabean簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Javabean簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了Javabean簡(jiǎn)介,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • spring boot裝載自定義yml文件

    spring boot裝載自定義yml文件

    這篇文章主要為大家詳細(xì)介紹了spring boot裝載自定義yml文件的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 高吞吐、線程安全的LRU緩存詳解

    高吞吐、線程安全的LRU緩存詳解

    這篇文章主要介紹了高吞吐、線程安全的LRU緩存詳解,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • 詳細(xì)分析java 動(dòng)態(tài)代理

    詳細(xì)分析java 動(dòng)態(tài)代理

    這篇文章主要介紹了java 動(dòng)態(tài)代理的的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • spring boot項(xiàng)目導(dǎo)入依賴(lài)后代碼報(bào)錯(cuò)問(wèn)題的解決方法

    spring boot項(xiàng)目導(dǎo)入依賴(lài)后代碼報(bào)錯(cuò)問(wèn)題的解決方法

    這篇文章主要給大家介紹了關(guān)于spring boot項(xiàng)目導(dǎo)入依賴(lài)后代碼報(bào)錯(cuò)問(wèn)題的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java多個(gè)版本切換的幾種方法

    Java多個(gè)版本切換的幾種方法

    本文主要介紹了Java多個(gè)版本切換的幾種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 使用SpringBoot簡(jiǎn)單實(shí)現(xiàn)無(wú)感知的刷新 Token功能

    使用SpringBoot簡(jiǎn)單實(shí)現(xiàn)無(wú)感知的刷新 Token功能

    實(shí)現(xiàn)無(wú)感知的刷新 Token 是一種提升用戶(hù)體驗(yàn)的常用技術(shù),可以在用戶(hù)使用應(yīng)用時(shí)自動(dòng)更新 Token,無(wú)需用戶(hù)手動(dòng)干預(yù),這種技術(shù)在需要長(zhǎng)時(shí)間保持用戶(hù)登錄狀態(tài)的應(yīng)用中非常有用,以下是使用Spring Boot實(shí)現(xiàn)無(wú)感知刷新Token的一個(gè)場(chǎng)景案例和相應(yīng)的示例代碼
    2024-09-09
  • Gradle的安裝和IDEA集成、項(xiàng)目導(dǎo)入的詳細(xì)教程

    Gradle的安裝和IDEA集成、項(xiàng)目導(dǎo)入的詳細(xì)教程

    這篇文章主要介紹了Gradle的安裝和IDEA集成、項(xiàng)目導(dǎo)入的詳細(xì)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java的作業(yè)調(diào)度類(lèi)庫(kù)Quartz基本使用指南

    Java的作業(yè)調(diào)度類(lèi)庫(kù)Quartz基本使用指南

    這篇文章主要介紹了Java的作業(yè)調(diào)度類(lèi)庫(kù)Quartz基本使用指南,Quartz能夠讓類(lèi)按照指定的計(jì)劃順序執(zhí)行,需要的朋友可以參考下
    2016-03-03
  • 基于SpringBoot創(chuàng)建Web頁(yè)面并熱更新的操作步驟

    基于SpringBoot創(chuàng)建Web頁(yè)面并熱更新的操作步驟

    SpringBoot是一個(gè)用于快速開(kāi)發(fā)單個(gè)微服務(wù)的框架,它基于 Spring 框架,簡(jiǎn)化了Spring應(yīng)用的初始化過(guò)程和開(kāi)發(fā)流程,本文給大家介紹了如何基于SpringBoot創(chuàng)建Web頁(yè)面并熱更新,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11

最新評(píng)論