精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

面試官:說說類加載的幾個階段

開發(fā) 前端
當一個類加載器負責加載某個Class文件時,該Class所依賴的和引用的其他Class也將由該類加載器負責載入,除非顯示使用另外一個類加載器來加載。

一、摘要

我們知道 Java 是先通過編譯器將.java類文件轉成.class字節(jié)碼文件,然后再通過虛擬機將.class字節(jié)碼文件加載到內(nèi)存中來實現(xiàn)應用程序的運行。

那么虛擬機是什么時候加載class文件?如何加載class文件?class文件進入到虛擬機后發(fā)生了哪些變化?

今天我們就一起來了解一下,虛擬機是如何加載類文件的。

二、類加載的時機

經(jīng)常有面試官問,“類什么時候加載”和“類什么時候初始化”,從內(nèi)容上來說,似乎都在問同一個問題:class文件是什么時候被虛擬機加載到內(nèi)存中,并進入可以使用的狀態(tài)?

從虛擬機角度來說,加載和初始化是類的加載過程中的兩個階段。

對于“什么時候加載”,Java 虛擬機規(guī)范中并沒有約束,每個虛擬機實例都可以按自身需要來自由實現(xiàn)。但基本上都遵循類在進行初始化之前,需要先進行加載class文件。

對于“什么時候初始化”,Java 虛擬機規(guī)范有明確的規(guī)定,當符合以下條件時(包括但不限),并且虛擬機在內(nèi)存中沒有找到對應的類信息,必須對類進行“初始化”操作:

  • 使用new實例化對象時,讀取或者設置一個類的靜態(tài)字段或方法時
  • 反射調(diào)用時,例如Class.forName("com.xxx.Test")
  • 初始化一個類的子類,會首先初始化子類的父類
  • Java 虛擬機啟動時標明的啟動類,比如main方法所在的類
  • JDK8 之后,接口中存在default方法,這個接口的實現(xiàn)類初始化時,接口會在它之前進行初始化

類在初始化開始之前,需要先經(jīng)歷加載、驗證、準備、解析這四個階段的操作。

下面我們一起來看看類的加載過程。

三、類的加載過程

當一個類需要被加載到虛擬機中執(zhí)行時,虛擬機會通過類加載器,將其.class文件中的字節(jié)碼信息在內(nèi)存中轉化成一個具體的java.lang.Class對象,以便被調(diào)用執(zhí)行。

類從被加載到虛擬機內(nèi)存中開始,到卸載出內(nèi)存,整個生命周期包括七個階段:加載、驗證、準備、解析、初始化、使用和卸載,可以用如下圖來簡要概括。

圖片圖片

其中類加載的過程,可以用三個步驟(五個階段)來簡要描述:加載 -> 連接(驗證、準備、解析)-> 初始化。(驗證、準備、解析這3個階段統(tǒng)稱為連接)

其次加載、驗證、準備和初始化這四個階段發(fā)生的順序是確定的,必須按照這種順序按部就班的開始,而解析階段則不一定。在某些情況下解析階段可以在初始化階段之后開始,這是為了支持 Java 語言的運行時綁定,也稱為動態(tài)綁定或晚期綁定。

同時,這五個階段并不是嚴格意義上的按順序完成,在類加載的過程中,這些階段會互相混合,可能有些階段完成了,有些階段沒有完成,會交叉運行,最終完成類的加載和初始化。

接下來依此分解一下加載、驗證、準備、解析、初始化這五個步驟,這五個步驟組成了一個完整的類加載過程。使用沒什么好說的,卸載通常屬于 GC 的工作,當一個類沒有被任何地方引用并且類加載器已被 GC 回收,GC 會將當前類進行卸載,在后續(xù)的文章我們會介紹 GC 的工作機制。

3.1、加載

加載是類加載的過程的第一個階段,這個階段的主要工作是查找并加載類的二進制數(shù)據(jù),在虛擬機中,類的加載有兩種觸發(fā)方式:

  • 預先加載:指的是虛擬機啟動時加載,例如JAVA_HOME/lib/下的rt.jar下的.class文件,這個jar包里面包含了程序運行時常用的文件內(nèi)容,例如java.lang.*、java.util.*、java.io.*等等,因此會隨著虛擬機啟動時一起加載到內(nèi)存中。要證明這一點很簡單,自己可以寫一個空的main函數(shù),設置虛擬機參數(shù)為-XX:+TraceClassLoading,運行程序就可以獲取類加載的全部信息
  • 運行時加載:虛擬機在用到一個.class文件的時候,會先去內(nèi)存中查看一下這個.class文件有沒有被加載,如果沒有,就會按照類的全限定名來加載這個類;如果有,就不會加載。

無論是哪種觸發(fā)方式,虛擬機在加載.class文件時,都會做以下三件事情:

  • 1.通過類的全限定名定位.class文件,并獲取其二進制字節(jié)流
  • 2.將類信息、靜態(tài)變量、字節(jié)碼、常量這些.class文件中的內(nèi)容放入運行時數(shù)據(jù)區(qū)的方法區(qū)中
  • 3.在內(nèi)存中生成一個代表這個.class文件的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口,一般這個java.lang.Class對象會存在 Java 堆中

虛擬機規(guī)范對這三點的要求并不具體,因此具體虛擬機實現(xiàn)的靈活度都很大。比如第一條,沒有指明二進制字節(jié)流要從哪里來,單單就這一條,就能變出許多花樣來,比如下面幾種加載方式:

  • 從 zip、jar、ear、war 等歸檔文件中加載.class文件
  • 通過網(wǎng)絡下載并加載.class文件,典型應用就是 Applet
  • 將Java源文件動態(tài)編譯為.class文件,典型應用就是動態(tài)代理技術
  • 從數(shù)據(jù)庫中提取.class文件并進行加載

總的來說,加載階段(準確地說,是加載階段獲取類的二進制字節(jié)流的動作)對于開發(fā)者來說是可控性最強的一個階段。因為開發(fā)者既可以使用系統(tǒng)提供的類加載器來完成加載,也可以自定義類加載器來完成加載。

3.2、驗證

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

Java 語言本身是比較安全的語言,但是正如上面說到的.class文件未必是從 Java 源碼編譯而來,可以使用任何途徑來生成并加載。虛擬機如果不檢查輸入的字節(jié)流,對其完全信任的話,很可能會因為載入了有害的字節(jié)流而導致系統(tǒng)崩潰,所以驗證是虛擬機對自身保護的一項重要工作。

驗證階段大致會完成 4 項檢驗工作:

  • 文件格式驗證:驗證字節(jié)流是否符合Class文件格式的規(guī)范,例如:是否以0xCAFEBABE開頭、主次版本號是否在當前虛擬機的處理范圍之內(nèi)、常量池中的常量是否有不被支持的類型等
  • 元數(shù)據(jù)驗證:對字節(jié)碼描述的元數(shù)據(jù)信息進行語義分析,要符合 Java 語言規(guī)范,例如:是否繼承了不允許被繼承的類(例如 final 修飾過的)、類中的字段、方法是否和父類產(chǎn)生矛盾等等
  • 字節(jié)碼驗證:對類的方法體進行校驗分析,確保這些方法在運行時是合法的、符合邏輯的
  • 符號引用驗證:確保解析動作能正確執(zhí)行,例如:確保符號引用的全限定名能找到對應的類,符號引用中的類、字段、方法允許被當前類所訪問等等

驗證階段是非常重要的,但不是必須的,它對程序運行期沒有影響,如果所引用的類經(jīng)過反復驗證,那么可以考慮采用-Xverify:none參數(shù)來關閉大部分的類驗證措施,以縮短虛擬機類加載的時間。

3.3、準備

準備是連接階段的第二步,這個階段的主要工作是正式為類變量分配內(nèi)存并設置其初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中分配。

不過這個階段,有幾個知識點需要注意一下:

  • 1.這時候進行內(nèi)存分配的僅僅是類變量(被static修飾的變量),而不是實例變量,實例變量將會在對象實例化的時候隨著對象一起分配在 Java 堆中
  • 2.這個階段會設置變量的初始值,值為數(shù)據(jù)類型默認的零值(如 0、0L、null、false 等),不是在代碼中被顯式地賦予的值;但是當字段被final修飾時,這個初始值就是代碼中顯式地賦予的值
  • 3.在 JDK1.8 取消永久代后,方法區(qū)變成了一個邏輯上的區(qū)域,這些類變量的內(nèi)存實際上是分配在 Java 堆中的,跟 JDK1.7 及以前的版本稍有不同

關于第二個知識點,我們舉個簡單的例子進行講解,比如public static int value = 123,value在準備階段過后是0而不是123。

因為這時候尚未開始執(zhí)行任何 Java 方法,把value賦值為123的public static指令是在程序編譯后存放于類構造器<clinit>()方法之中的,因此把value賦值為123的動作將在初始化階段才會執(zhí)行。

假如被final修飾,比如public static final int value = 123就不一樣了,編譯時Javac將會為value生成ConstantValue屬性,在準備階段,虛擬機就會給value賦值為123,因為這個變量無法被修改,會存入類的常量池中。

各個數(shù)據(jù)類型的零值如下圖:

數(shù)據(jù)類型

零值

byte

0

short

0

int

0

long

0L

float

0.0f

double

0.0d

boolean

false

char

\u0000

reference

null

3.4、解析

解析是連接階段的第三步,這個階段的主要工作是虛擬機會把這個.class文件中常量池內(nèi)的符號引用轉換為直接引用。

主要解析的是類或接口、字段、方法等符號引用,我們可以把解析階段中符號引用轉換為直接引用的過程,理解為當前加載的這個類和它所引用的類,正式進行“連接“的過程。

我們先來了解一下符號引用和直接引用有什么區(qū)別:

  • 符號引用:這個其實是屬于編譯原理方面的概念,Java 代碼在編譯期間,是不知道最終引用的類型,具體指向內(nèi)存中哪個位置的,這時候會使用一個符號引用來表示具體引用的目標是"誰",符號引用和虛擬機的內(nèi)存布局是沒有關系的
  • 直接引用:指的是可以直接或間接指向目標內(nèi)存位置的指針或句柄,直接引用和虛擬機實現(xiàn)的內(nèi)存布局是有關系的

符號引用轉換為直接引用,可以理解成將某個符號與虛擬機中的內(nèi)存位置建立連接,通過指針或句柄來直接訪問目標。

與此同時,同一個符號引用在不同的虛擬機實現(xiàn)上翻譯出來的直接引用一般不會相同。

3.5、初始化

初始化是類加載的過程的最后一步,這個階段的主要工作是執(zhí)行類構造器 <clinit>()方法的過程。

簡單的說,初始化階段做的事就是給static變量賦予用戶指定的值,同時類中如果存在static代碼塊,也會執(zhí)行這個靜態(tài)代碼塊里面的代碼。

初始化階段,虛擬機大致依此會進行如下幾個步驟的操作:

  • 1.檢查這個類是否被加載和連接,如果沒有,則程序先加載并連接該類
  • 2.檢查該類的直接父類有沒有被初始化,如果沒有,則先初始化其直接父類
  • 3.類中如果有多個初始化語句,比如多個static代碼塊,則依次執(zhí)行這些初始化語句

有個地方需要注意的是:虛擬機會保證類的初始化在多線程環(huán)境中被正確地加鎖、同步執(zhí)行,所以無需擔心是否會出現(xiàn)變量初始化時線程不安全的問題。

如果多個線程同時去初始化一個類,那么只會有一個線程去執(zhí)行這個類的<clinit>()方法,其他線程都會阻塞等待,直到<clinit>()方法執(zhí)行完畢。同時,同一個類加載器下,一個類只會初始化一次,如果檢查到當前類沒有初始化,執(zhí)行初始化;反之,不會執(zhí)行初始化。

與此同時,只有當對類的主動使用的時候才會觸發(fā)類的初始化,觸發(fā)時機主要有以下幾種場景:

  • 1.創(chuàng)建類的實例對象,比如new一個對象操作
  • 2.訪問某個類或接口的靜態(tài)變量,或者對該靜態(tài)變量賦值
  • 3.調(diào)用類的靜態(tài)方法
  • 4.反射操作,比如Class.forName("xxx")
  • 5.初始化某個類的子類,則其父類也會被初始化,并且父類具有優(yōu)先被初始化的優(yōu)勢
  • 6.Java 虛擬機啟動時被標明為啟動類的類,比如SpringBootApplication入口類

最后,<clinit>()方法和<init>()方法是不同的,一個是類構造器初始化,一個是實例構造器初始化,千萬別搞混淆了啊。

3.6、小結

當一個符合 Java 虛擬機規(guī)范的.class字節(jié)碼文件,經(jīng)歷加載、驗證、準備、解析、初始化這些 5 個階段相互協(xié)作執(zhí)行完成之后,虛擬機會將此文件的二進制數(shù)據(jù)導入運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆內(nèi)存中,創(chuàng)建一個java.lang.Class類的對象,這個對象描述了這個類所有的信息,同時提供了這個類在方法區(qū)的訪問入口。

可以用如下圖來簡要描述。

圖片圖片

與此同時,在方法區(qū)中,使用同一加載器的情況下,每個類只會有一份Class字節(jié)流信息;在堆內(nèi)存中,使用同一加載器的情況下,每個類也只會有一份java.lang.Class類的對象。

四、類加載器

在上文類的加載過程中,我們有提到在加載階段,通過一個類的全限定名來獲取此類的二進制字節(jié)流操作,其實類加載器就是用來實現(xiàn)這個操作的。

在虛擬機中,任何一個類,都需要由加載它的類加載器和這個類本身一同確立其唯一性,每一個類加載器,都擁有一個獨立的類名稱空間,對于類也同樣如此。

簡單的說,在虛擬機中看兩個類是否相同,只有在這兩個類是由同一個類加載器加載的前提下才有意義,否則即使這兩個類來源于同一個.class文件,被同一個虛擬機加載,但是它們的類加載器不同,這兩個類必定不相等。

當年為了滿足瀏覽器上 Java Applet 的需求,Java 的開發(fā)團隊設計了類加載器,它獨立于 Java 虛擬機外部,同時也允許用戶按自身需要自行實現(xiàn)類加載器。通過類加載器,可以讓同一個類可以實現(xiàn)訪問隔離、OSGi、程序熱部署等等場景。發(fā)展至今,類加載器已經(jīng)是 Java 技術體系的一塊重要基石。

4.1、類加載器介紹

如果要查找類加載器,通過Thread.currentThread().getContextClassLoader()方法可以獲取。

簡單示例如下:

public class ClassLoaderTest {

    public static void main(String[] args) {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        System.out.println("current loader:" +  loader);
        System.out.println("parent loader:" +  loader.getParent());
        System.out.println("parent parent loader:" +  loader.getParent().getParent());
    }
}

輸出結果如下:

current loader:sun.misc.Launcher$AppClassLoader@18b4aac2
parent loader:sun.misc.Launcher$ExtClassLoader@511d50c0
parent parent loader:null

從運行結果可以看到,當前的類加載器是AppClassLoader,它的上一級是ExtClassLoader,再上一級是null。

其實ExtClassLoader的上一級是有類加載器的,它叫Bootstrap ClassLoader,是一個啟動類加載器,由 C++ 實現(xiàn),不是 ClassLoader 子類,因此以 null 作為結果返回。

這幾種類加載器的層次關系,可以用如下圖來描述。

圖片圖片

它們之間的啟動流程,可以通過以下內(nèi)容來簡單描述:

  • 1.在虛擬機啟動后,會優(yōu)先初始化Bootstrap Classloader
  • 2.接著Bootstrap Classloader負責加載ExtClassLoader,并且將 ExtClassLoader的父加載器設置為Bootstrap Classloader
  • 3Bootstrap Classloader加載完ExtClassLoader后,就會加載AppClassLoader,并且將AppClassLoader的父加載器指定為 ExtClassLoader

因此,在加載 Java 應用程序中的class文件時,這里的父類加載器并不是通過繼承關系來實現(xiàn)的,而是互相配合進行加載。

站在虛擬機的角度,只存在兩種不同的類加載器:

  • 啟動類加載器:它由 C++ 實現(xiàn)(這里僅限于 Hotspot,不同的虛擬機可能實現(xiàn)不太一樣),是虛擬機自身的一部分
  • 其它類加載器:這些類加載器都由 Java 實現(xiàn),獨立于虛擬機之外,并且全部繼承自抽象類java.lang.ClassLoader,比如ExtClassLoader、AppClassLoader等,這些類加載器需要由啟動類加載器加載到內(nèi)存中之后才能去加載其他的類

站在開發(fā)者的角度,類加載器大致可以劃分為三類:

  • 啟動類加載器:比如Bootstrap ClassLoader,負責加載<JAVA_HOME>\lib目錄,或者被-Xbootclasspath參數(shù)制定的路徑,例如jre/lib/rt.jar里所有的class文件。同時,啟動類加載器是無法被 Java 程序直接引用的
  • 拓展類加載器:比如Extension ClassLoader,負責加載 Java 平臺中擴展功能的一些 jar 包,包括<JAVA_HOME>\lib\ext目錄中或java.ext.dirs指定目錄下的 jar 包。同時,開發(fā)者可以直接使用擴展類加載器
  • 應用程序類加載器:比如Application ClassLoader,負責加載ClassPath路徑下所有 jar 包,如果應用程序中沒有自定義過自己的類加載器,一般情況下它就是程序中默認的類加載器

當然,如果有必要,也可以自定義類加載器,因為 JVM 自帶的 ClassLoader 只懂得從本地文件系統(tǒng)中加載標準的class文件,如果要從特定的場所取得class文件,例如數(shù)據(jù)庫中和網(wǎng)絡中,此時可以自己編寫對應的 ClassLoader 類加載器。

4.2、雙親委派模型

在上文中我們提到,在虛擬機中,任何一個類由加載它的類加載器和這個類一同來確立其唯一性。

也就是說,JVM 對類的唯一標識,可以簡單的理解為由ClassLoader id + PackageName + ClassName組成,因此在一個運行程序中有可能存在兩個包名和類名完全一致的類,但是如果這兩個類不是由一個 ClassLoader 加載,會被視為兩個不同的類,此時就無法將一個類的實例強轉為另外一個類,這就是類加載器的隔離性。

為了解決類加載器的隔離問題,JVM 引入了雙親委派模型。

雙親委派模式,可以用一句話來說表達:任何一個類加載器在接到一個類的加載請求時,都會先讓其父類進行加載,只有父類無法加載(或者沒有父類)的情況下,才嘗試自己加載。

大致流程圖如下:

圖片圖片

使用雙親委派模式,可以保證,每一個類只會有一個類加載器。例如 Java 最基礎的 Object 類,它存放在 rt.jar 之中,這是 Bootstrap 的職責范圍,當向上委派到 Bootstrap 時就會被加載。

但如果沒有使用雙親委派模式,可以任由自定義加載器進行加載的話,Java 這些核心類的 API 就會被隨意篡改,無法做到一致性加載效果。

JDK 中ClassLoader.loadClass()類加載器中的加載類的方法,部分核心源碼如下:

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
{
    // 1.首先要保證線程安全
    synchronized (getClassLoadingLock(name)) {
        // 2.先判斷這個類是否被加載過,如果加載過,直接跳過
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                // 3.有父類,優(yōu)先交給父類嘗試加載;如果為空,使用BootstrapClassLoader類加載器
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // 父類加載失敗,這里捕獲異常,但不需要做任何處理
            }

            // 4.沒有父類,或者父類無法加載,嘗試自己加載
            if (c == null) {
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

4.3、自定義類加載器

在上文中我們提及過,針對某些特定場景,比如通過網(wǎng)絡來傳輸 Java 類的字節(jié)碼文件,為保證安全性,這些字節(jié)碼經(jīng)過了加密處理,這時系統(tǒng)提供的類加載器就無法對其進行加載,此時我們可以自定義一個類加載器來完成文件的加載。

自定義類加載器也需要繼承ClassLoader類,簡單示例如下:

public class CustomClassLoader extends ClassLoader {

    private String classPath;

    public CustomClassLoader(String classPath) {
        this.classPath = classPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            byte[] data = loadClassData(name);
            if (data == null) {
                throw new ClassNotFoundException();
            }
            return defineClass(name, data, 0, data.length);
        }
        return null;
    }

    protected byte[] loadClassData(String name) {
        try {
            // package -> file folder
            name = name.replace(".", "http://");
            FileInputStream fis = new FileInputStream(new File(classPath + "http://" + name + ".class"));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len = -1;
            byte[] b = new byte[2048];
            while ((len = fis.read(b)) != -1) {
                baos.write(b, 0, len);
            }
            fis.close();
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

相關的測試類如下:

package com.example;

public class ClassLoaderTest {

    public static void main(String[] args) {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        System.out.println("current loader:" +  loader);
    }
}

將ClassLoaderTest.java源文件放在指定目錄下,并通過javac命令編譯成ClassLoaderTest.class,最后進行測試。

public class CustomClassLoaderTest {

    public static void main(String[] args) throws Exception {
        String classPath = "/Downloads";
        CustomClassLoader customClassLoader = new CustomClassLoader(classPath);
        Class<?> testClass = customClassLoader.loadClass("com.example.ClassLoaderTest");
        Object obj = testClass.newInstance();
        System.out.println(obj.getClass().getClassLoader());
    }
}

輸出結果:

com.example.CustomClassLoader@60e53b93

在實際使用過程中,最好不要重寫loadClass方法,避免破壞雙親委派模型。

4.4、加載類的幾種方式

在類加載器中,有三種方式可以實現(xiàn)類的加載。

  • 1.通過命令行啟動應用時由 JVM 初始化加載,在上文已提及過
  • 2.通過Class.forName()方法動態(tài)加載
  • 3.通過ClassLoader.loadClass()方法動態(tài)加載

其中Class.forName()和ClassLoader.loadClass()加載方法,稍有區(qū)別:

  • Class.forName():表示將類的.class文件加載到 JVM 中之后,還會對類進行解釋,執(zhí)行類中的static方法塊;
  • Class.forName(name, initialize, loader):支持通過參數(shù)來控制是否執(zhí)行類中的static方法塊;
  • ClassLoader.loadClass():它只將類的.class文件加載到 JVM,但是不執(zhí)行類中的static方法塊,只有在newInstance()才會去執(zhí)行static方法塊;

我們可以看一個簡單的例子!

public class ClassTest {

    static {
        System.out.println("初始化靜態(tài)代碼塊!");
    }
}
public class CustomClassLoaderTest {

    public static void main(String[] args) throws Exception {
        // 獲取當前系統(tǒng)類加載器
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        // 1.使用Class.forName()來加載類,默認會執(zhí)行初始化靜態(tài)代碼塊
        Class.forName(ClassTest.class.getName());

        // 2.使用Class.forName()來加載類,指定false,不會執(zhí)行初始化靜態(tài)代碼塊
//        Class.forName(ClassTest.class.getName(), false, classLoader);

        // 3.使用ClassLoader.loadClass()來加載類,不會執(zhí)行初始化靜態(tài)代碼塊
//        classLoader.loadClass(ClassTest.class.getName());
    }
}

運行結果如下:

初始化靜態(tài)代碼塊!

切換不同的加載方式,會有不同的輸出結果!

4.5、小結

從以上的介紹中,針對類加載器的機制,我們可以總結出以下幾點:

  • 全盤負責:當一個類加載器負責加載某個Class文件時,該Class所依賴的和引用的其他Class也將由該類加載器負責載入,除非顯示使用另外一個類加載器來加載
  • 雙親委派:在接受類加載請求時,會讓父類加載器試圖加載該類,只有在父類加載器無法加載該類或者沒有父類時,才嘗試從自己的類路徑中加載該類
  • 按需加載:用戶創(chuàng)建的類,通常加載是按需進行的,只有使用了才會被類加載器加載
  • 緩存機制:有被加載過的Class文件都會被緩存,當要使用某個Class時,會先去緩存查找,如果緩存中沒有才會讀取Class文件進行加載。這就是為什么修改了Class文件后,必須重啟 JVM,程序的修改才會生效的原因

五、小結

本文從類的加載過程到類加載器,做了一次知識內(nèi)容講解,內(nèi)容比較多,如果有描述不對的地方,歡迎大家留言指出,不勝感激!

六、參考

1.https://zhuanlan.zhihu.com/p/25228545

2.http://www.ityouknow.com/jvm/2017/08/19/class-loading-principle.html

3.https://www.cnblogs.com/xrq730/p/4844915.html

4.https://www.cnblogs.com/xrq730/p/4845144.html

責任編輯:武曉燕 來源: Java極客技術
相關推薦

2024-11-19 15:13:02

2025-04-16 00:00:01

JWT客戶端存儲加密令

2023-12-27 18:16:39

MVCC隔離級別幻讀

2025-04-08 00:00:00

@AsyncSpring異步

2024-08-22 10:39:50

@Async注解代理

2024-03-05 10:33:39

AOPSpring編程

2024-05-30 08:04:20

Netty核心組件架構

2024-03-14 14:56:22

反射Java數(shù)據(jù)庫連接

2021-11-25 10:18:42

RESTfulJava互聯(lián)網(wǎng)

2024-07-31 08:28:37

DMAIOMMap

2024-12-06 07:00:00

2024-09-20 08:36:43

零拷貝數(shù)據(jù)傳輸DMA

2024-03-11 18:18:58

項目Spring線程池

2024-03-22 06:56:24

零拷貝技術數(shù)據(jù)傳輸數(shù)據(jù)拷貝

2021-08-09 07:47:40

Git面試版本

2020-07-02 07:52:11

RedisHash映射

2024-02-29 16:49:20

volatileJava并發(fā)編程

2024-08-29 16:30:27

2024-08-12 17:36:54

2021-07-28 10:08:19

類加載代碼塊面試
點贊
收藏

51CTO技術棧公眾號

日韩毛片免费视频一级特黄| 69久久精品| 中文亚洲字幕| 亚洲三级 欧美三级| wwwwwxxxx日本| 欧美人体视频xxxxx| 26uuu精品一区二区| 国产欧美日韩视频| 日本中文字幕网| 日韩电影一区| 日韩精品极品在线观看| 日本不卡一区二区在线观看| a在线视频v视频| 国产精品久久久爽爽爽麻豆色哟哟| 91在线国产电影| 一区二区三区在线观看av| 亚洲精品小说| 亚洲天堂成人在线视频| 国产调教打屁股xxxx网站| 第四色男人最爱上成人网| 一区二区欧美国产| 亚洲乱码一区二区三区| 日韩一区二区三区不卡| 极品少妇xxxx偷拍精品少妇| 欧美一性一乱一交一视频| 国产盗摄x88av| 秋霞欧美视频| 亚洲精品视频免费在线观看| 久久久久亚洲AV成人网人人小说| jizz久久久久久| 欧美日韩一区二区三区在线免费观看| 91麻豆天美传媒在线| 日本成人一区| 成人a区在线观看| 91在线无精精品一区二区| 日韩精品在线一区二区三区| 亚洲日本国产| 欧美国产在线视频| 欧美成欧美va| 五月激情综合| 久久精品成人欧美大片古装| 阿v天堂2014| 精品久久美女| 亚洲日韩第一页| 亚洲最大的黄色网| 激情小说一区| 亚洲电影免费观看高清完整版在线观看 | 91在线观看网站| 97视频免费在线| 精品一区二区三区欧美| 国产精品色午夜在线观看| 国产一区二区视频网站| 久久久久免费| 国产精品久久91| 真实新婚偷拍xxxxx| 丝袜诱惑制服诱惑色一区在线观看 | 久久er99热精品一区二区三区| 国内爆初菊对白视频| 国产999精品久久| 99国产视频| 亚洲黄色小说网址| jvid福利写真一区二区三区| 精品不卡一区二区三区| 午夜福利视频一区二区| 99精品热视频| 秋霞久久久久久一区二区| 国产小视频在线| 中日韩av电影| 秋霞在线一区二区| 国产精品偷拍| 色呦呦国产精品| 天天操天天摸天天爽| 男女啪啪999亚洲精品| 91.成人天堂一区| 中文字幕一区二区三区人妻在线视频 | 在线观看男女av免费网址| 一区二区三区四区中文字幕| 久久人妻无码一区二区| 天堂电影一区| 欧美性猛片aaaaaaa做受| 激情文学亚洲色图| 97久久综合区小说区图片区| 日韩激情片免费| 91精品久久久久久久久久久久| 欧美xxxx中国| 97国产一区二区精品久久呦| 国产精品尤物视频| 国产精品一卡二卡| 鲁丝一区二区三区免费| 黄色网址视频在线观看| 亚洲一区二区三区四区的| 欧洲黄色一级视频| 亚洲精品aa| 亚洲精品国产精品久久清纯直播 | 在线看免费毛片| 精品五月天堂| 日韩中文字幕在线看| 国产午夜视频在线| 免费成人小视频| 国产精品视频福利| 色网站在线看| 欧美特级www| www.日本久久| 精品国产91乱码一区二区三区四区 | 亚洲第一香蕉网| 99久久亚洲精品蜜臀| 91av在线不卡| 国产视频在线一区| 久久精品人人爽人人爽| 欧美人与动牲交xxxxbbbb| 全球最大av网站久久| 精品久久久久久亚洲综合网| 日本美女xxx| 亚洲美女色禁图| 92看片淫黄大片看国产片| 亚洲三区在线观看无套内射| 亚洲欧美在线观看| 国产精品-区区久久久狼| 91成人短视频| 精品久久久999| 男人日女人网站| 成人av资源在线观看| 亚洲欧洲一区二区福利| 在线免费日韩片| 亚洲成人av资源网| 国产精品成人免费观看| 久久99久久久欧美国产| 欧美在线一二三区| 日韩脚交footjobhd| 欧美xxxxxxxxx| 欧美做爰啪啪xxxⅹ性| 美国十次了思思久久精品导航| 久久精品国产第一区二区三区最新章节 | 精品人妻无码中文字幕18禁| 欧美gvvideo网站| 国产精品一区二区久久久| 青青草视频免费在线观看| 亚洲电影在线免费观看| 乱码一区二区三区| 欧美午夜精品| 99re视频在线观看| 天天色天天射天天综合网| 4438成人网| 男人操女人的视频网站| 九九久久精品视频| 亚洲自拍的二区三区| 激情小说亚洲| 日韩性生活视频| 国产精品老熟女视频一区二区| 国产精品久久免费看| 爱爱爱爱免费视频| 99tv成人| 91影院未满十八岁禁止入内| 免费在线播放电影| 亚洲第一区在线观看| 男女啊啊啊视频| 91免费在线看| 北条麻妃在线一区| 成人中文在线| 亚洲va欧美va国产综合剧情| 香蕉成人app免费看片| 精品sm在线观看| 日本熟女毛茸茸| 国产免费久久精品| 亚洲黄色av片| 欧美三区在线| 欧美成ee人免费视频| 91精品韩国| 精品国偷自产在线| 亚洲国产精品suv| 高跟丝袜欧美一区| 欧美午夜激情影院| 国产一区二区福利视频| 我的公把我弄高潮了视频| 网红女主播少妇精品视频| 国产精品高潮视频| 成人在线直播| 日韩第一页在线| 中文无码av一区二区三区| 亚洲视频你懂的| 99久久国产精| 国内精品久久久久影院薰衣草| 欧美一区二区三区综合| 亚洲精品一级二级三级| 国产日韩欧美另类| 97天天综合网| 中文字幕久久亚洲| 高潮一区二区三区乱码| 色94色欧美sute亚洲13| 超碰在线国产97| 久久综合中文字幕| 波多野结衣中文字幕在线播放| 亚洲少妇在线| www.99riav| 激情婷婷综合| 国产传媒一区二区| 国产精品66| 欧美亚洲激情视频| 四虎亚洲精品| 伊人男人综合视频网| 手机在线精品视频| 91精品午夜视频| 国产精品熟女视频| 亚洲成人精品一区| 天天看天天摸天天操| 久久久久久久久岛国免费| 91香蕉国产线在线观看| 老司机精品视频网站| 亚洲国产精品成人天堂| 亚洲精品在线观看91| 欧美中日韩一区二区三区| 成人香蕉社区| 川上优av一区二区线观看| 性欧美1819sex性高清| 久久久噜久噜久久综合| 蜜桃av在线免费观看| 亚洲人成电影网站色xx| 日本免费网站在线观看| 一级特黄免费视频| 欧美色videos| 日本va欧美va国产激情| 亚洲综合免费观看高清在线观看| 亚洲色图第四色| 久久精品人人做| 精品人妻一区二区三区视频| av色综合久久天堂av综合| 国产伦精品一区二区三区妓女下载 | 欧美在线视频免费| 成人免费高清观看| 久久99国产综合精品女同| 麻豆免费在线观看| 中文字幕日韩av| 午夜在线播放| 中文字幕亚洲一区二区三区| 国产一区二区影视| 伊人久久五月天| 91视频在线观看| 精品久久久av| 国产盗摄在线观看| 欧美成人午夜激情| 菠萝菠萝蜜在线视频免费观看| 色偷偷噜噜噜亚洲男人的天堂| 福利在线观看| 国产一区二区激情| 成人性生交大片免费看午夜| 亚洲欧美日韩图片| 国产h在线观看| 中文字幕精品av| 一本一道波多野毛片中文在线| 中文字幕成人精品久久不卡| 午夜在线小视频| 久久最新资源网| 日本色护士高潮视频在线观看| 九九热精品视频在线播放| 制服丝袜中文字幕在线| 欧美激情精品久久久久久免费印度| 男女视频在线| 91av网站在线播放| 精品视频在线一区二区在线| 国产精品亚洲激情| 国产一精品一av一免费爽爽| 91丨九色丨国产| 任你弄精品视频免费观看| 欧美成人免费在线| 久久一区91| 99热久久这里只有精品| 国产精品亚洲产品| 日韩爱爱小视频| 国产精品99久久不卡二区| 天天躁日日躁狠狠躁免费麻豆| av一区二区久久| 五月天精品视频| 中文字幕一区视频| 精品小视频在线观看| 欧美午夜电影在线| 亚洲影视一区二区| 精品久久一区二区| 九色视频在线播放| 久久五月天综合| 女海盗2成人h版中文字幕| 国产成人精品综合| 国产专区精品| 蜜桃麻豆91| 五月精品视频| 北条麻妃在线视频观看| 另类的小说在线视频另类成人小视频在线| www.51色.com| 国产亚洲一本大道中文在线| 91狠狠综合久久久| 黑人狂躁日本妞一区二区三区| 亚洲无码精品国产| 亚洲第一精品自拍| 老司机99精品99| 69av在线视频| av日韩一区| 欧洲亚洲一区| 欧美日韩国产一区精品一区| 成人免费毛片播放| 高清日韩电视剧大全免费| 国产aⅴ激情无码久久久无码| 亚洲乱码国产乱码精品精的特点| 最近免费中文字幕大全免费版视频| 538在线一区二区精品国产| 日本黄在线观看| 九九热精品在线| 欧美成人福利| 奇米影视首页 狠狠色丁香婷婷久久综合 | 国产成人a亚洲精v品无码| 国产剧情一区二区| 成熟人妻av无码专区| 亚洲成av人片在线观看无码| 91久久精品无码一区二区| 亚洲精品一区二区三区不| 欧美性video| 国产专区欧美专区| 欧美美女一区| 成年人观看网站| 不卡区在线中文字幕| 熟女av一区二区| 欧美私模裸体表演在线观看| 四虎影视2018在线播放alocalhost| 欧美尺度大的性做爰视频| 国产精品久久久久久久久久齐齐 | 欧美gay男男猛男无套| 色欲av无码一区二区人妻| 成人一级片在线观看| 国产一区二区播放| 欧美高清一级片在线| 北岛玲一区二区三区| 国产成人精品一区| 九九视频免费观看视频精品| 国产av天堂无码一区二区三区| 成人性视频免费网站| 劲爆欧美第一页| 欧美一级艳片视频免费观看| 欧美性天天影视| 成人免费观看网址| 911久久香蕉国产线看观看| 在线观看国产一级片| 亚洲国产精品激情在线观看| 高潮毛片又色又爽免费| 亚洲欧美日韩精品| 欧美日韩免费看片| 日本一区二区三区视频免费看| 老司机精品久久| 色撸撸在线视频| 欧美日韩免费不卡视频一区二区三区| shkd中文字幕久久在线观看| 国产精品国语对白| 日韩精品久久| www.久久av.com| 亚洲精品乱码久久久久久久久 | 成人在线高清| 亚洲欧美日本国产有色| 精品在线一区二区| a级黄色片免费看| 亚洲成人av在线| 9i看片成人免费高清| 日韩精品久久一区| 精品一区二区三区蜜桃| 欧美精品乱码视频一二专区| 欧美精品一区二区在线观看| 手机在线理论片| 视频一区视频二区视频三区高| 美女网站色91| 国产探花在线播放| 亚洲国产精品国自产拍av秋霞| 亚洲欧洲美洲av| 亚洲成人第一| 国产成人av电影| 日产精品久久久| www.欧美精品| 岛国精品一区| 欧美黄色一级片视频| 中文字幕一区二区不卡| 午夜精品久久久久久久91蜜桃| 91精品国产自产91精品| 日韩国产欧美| yjizz视频| 在线精品视频一区二区| 大片免费在线看视频| 久久久亚洲综合网站| 国内外成人在线视频| 日韩欧美三级视频| 综合国产在线视频| 超碰成人免费| 91制片厂毛片| 亚洲不卡一区二区三区| 99免在线观看免费视频高清| 成人动漫视频在线观看完整版 | 欧美久久影院| 国产精品久久久久久亚洲色 | 精品人妻aV中文字幕乱码色欲| 66m—66摸成人免费视频| 香蕉久久网站| 日韩中文字幕电影| 日韩一区二区在线播放| 香蕉久久免费电影| 日韩精品在线视频免费观看| 欧美国产一区二区|