中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java的類加載機制是什么

發布時間:2020-11-09 14:16:14 來源:億速云 閱讀:122 作者:小新 欄目:編程語言

小編給大家分享一下Java的類加載機制是什么,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!

01、字節碼

在聊 Java 類加載機制之前,需要先了解一下 Java 字節碼,因為它和類加載機制息息相關。

計算機只認識 0 和 1,所以任何語言編寫的程序都需要編譯成機器碼才能被計算機理解,然后執行,Java 也不例外。

Java 在誕生的時候喊出了一個非常牛逼的口號:“Write Once, Run Anywhere”,為了達成這個目的,Sun 公司發布了許多可以在不同平臺(Windows、Linux)上運行的 Java 虛擬機(JVM)——負責載入和執行 Java 編譯后的字節碼。

Java的類加載機制是什么

到底 Java 字節碼是什么樣子,我們借助一段簡單的代碼來看一看。

源碼如下:

package com.cmower.java_demo;

public class Test {

    public static void main(String[] args) {
        System.out.println("版權聲明");
    }

}

代碼編譯通過后,通過 xxd Test.class 命令查看一下這個字節碼文件。

xxd Test.class
00000000: cafe babe 0000 0034 0022 0700 0201 0019  .......4."......
00000010: 636f 6d2f 636d 6f77 6572 2f6a 6176 615f  com/cmower/java_
00000020: 6465 6d6f 2f54 6573 7407 0004 0100 106a  demo/Test......j
00000030: 6176 612f 6c61 6e67 2f4f 626a 6563 7401  ava/lang/Object.
00000040: 0006 3c69 6e69 743e 0100 0328 2956 0100  ..<init>...()V..
00000050: 0443 6f64 650a 0003 0009 0c00 0500 0601  .Code...........
00000060: 000f 4c69 6e65 4e75 6d62 6572 5461 626c  ..LineNumberTabl

感覺有點懵逼,對不對?

懵就對了。

這段字節碼中的 cafe babe 被稱為“魔數”,是 JVM 識別 .class 文件的標志。文件格式的定制者可以自由選擇魔數值(只要沒用過),比如說 .png 文件的魔數是 8950 4e47。

至于其他內容嘛,可以選擇忘記了。

02、類加載過程

了解了 Java 字節碼后,我們來聊聊 Java 的類加載過程。

Java 的類加載過程可以分為 5 個階段:載入、驗證、準備、解析和初始化。這 5 個階段一般是順序發生的,但在動態綁定的情況下,解析階段發生在初始化階段之后。

1)Loading(載入)

JVM 在該階段的主要目的是將字節碼從不同的數據源(可能是 class 文件、也可能是 jar 包,甚至網絡)轉化為二進制字節流加載到內存中,并生成一個代表該類的 java.lang.Class 對象。

2)Verification(驗證)

JVM 會在該階段對二進制字節流進行校驗,只有符合 JVM 字節碼規范的才能被 JVM 正確執行。該階段是保證 JVM 安全的重要屏障,下面是一些主要的檢查。

確保二進制字節流格式符合預期(比如說是否以 cafe bene 開頭)。

是否所有方法都遵守訪問控制關鍵字的限定。

方法調用的參數個數和類型是否正確。

確保變量在使用之前被正確初始化了。

檢查變量是否被賦予恰當類型的值。

3)Preparation(準備)

JVM 會在該階段對類變量(也稱為靜態變量,static 關鍵字修飾的)分配內存并初始化(對應數據類型的默認初始值,如 0、0L、null、false 等)。

也就是說,假如有這樣一段代碼:

public String chenmo = "沉默";
public static String wanger = "王二";
public static final String cmower = "沉默王二";

chenmo 不會被分配內存,而 wanger 會;但 wanger 的初始值不是“王二”而是 null。

需要注意的是,static final 修飾的變量被稱作為常量,和類變量不同。常量一旦賦值就不會改變了,所以 cmower 在準備階段的值為“沉默王二”而不是 null。

4)Resolution(解析)

該階段將常量池中的符號引用轉化為直接引用。

what?符號引用,直接引用?

符號引用以一組符號(任何形式的字面量,只要在使用時能夠無歧義的定位到目標即可)來描述所引用的目標。

在編譯時,Java 類并不知道所引用的類的實際地址,因此只能使用符號引用來代替。比如 com.Wanger 類引用了 com.Chenmo 類,編譯時 Wanger 類并不知道 Chenmo 類的實際內存地址,因此只能使用符號 com.Chenmo。

直接引用通過對符號引用進行解析,找到引用的實際內存地址。

5)Initialization(初始化)

該階段是類加載過程的最后一步。在準備階段,類變量已經被賦過默認初始值,而在初始化階段,類變量將被賦值為代碼期望賦的值。換句話說,初始化階段是執行類構造器方法的過程。

oh,no,上面這段話說得很抽象,不好理解,對不對,我來舉個例子。

String cmower = new String("沉默王二");

上面這段代碼使用了 new 關鍵字來實例化一個字符串對象,那么這時候,就會調用 String 類的構造方法對 cmower 進行實例化。

03、類加載器

聊完類加載過程,就不得不聊聊類加載器。

一般來說,Java 程序員并不需要直接同類加載器進行交互。JVM 默認的行為就已經足夠滿足大多數情況的需求了。不過,如果遇到了需要和類加載器進行交互的情況,而對類加載器的機制又不是很了解的話,就不得不花大量的時間去調試

ClassNotFoundException 和 NoClassDefFoundError 等異常。

對于任意一個類,都需要由它的類加載器和這個類本身一同確定其在 JVM 中的唯一性。也就是說,如果兩個類的加載器不同,即使兩個類來源于同一個字節碼文件,那這兩個類就必定不相等(比如兩個類的 Class 對象不 equals)。

站在程序員的角度來看,Java 類加載器可以分為三種。

1)啟動類加載器(Bootstrap Class-Loader),加載 jre/lib 包下面的 jar 文件,比如說常見的 rt.jar。

2)擴展類加載器(Extension or Ext Class-Loader),加載 jre/lib/ext 包下面的 jar 文件。

3)應用類加載器(Application or App Clas-Loader),根據程序的類路徑(classpath)來加載 Java 類。

來來來,通過一段簡單的代碼了解下。

public class Test {

	public static void main(String[] args) {
		ClassLoader loader = Test.class.getClassLoader();
		while (loader != null) {
			System.out.println(loader.toString());
			loader = loader.getParent();
		}
	}

}

每個 Java 類都維護著一個指向定義它的類加載器的引用,通過 類名.class.getClassLoader() 可以獲取到此引用;然后通過 loader.getParent() 可以獲取類加載器的上層類加載器。

這段代碼的輸出結果如下:

sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742

第一行輸出為 Test 的類加載器,即應用類加載器,它是 sun.misc.Launcher$AppClassLoader 類的實例;第二行輸出為擴展類加載器,是 sun.misc.Launcher$ExtClassLoader 類的實例。那啟動類加載器呢?

按理說,擴展類加載器的上層類加載器是啟動類加載器,但在我這個版本的 JDK 中, 擴展類加載器的 getParent() 返回 null。所以沒有輸出。

04、雙親委派模型

如果以上三種類加載器不能滿足要求的話,程序員還可以自定義類加載器(繼承 java.lang.ClassLoader 類),它們之間的層級關系如下圖所示。

Java的類加載機制是什么

這種層次關系被稱作為雙親委派模型:如果一個類加載器收到了加載類的請求,它會先把請求委托給上層加載器去完成,上層加載器又會委托上上層加載器,一直到最頂層的類加載器;如果上層加載器無法完成類的加載工作時,當前類加載器才會嘗試自己去加載這個類。

PS:雙親委派模型突然讓我聯想到朱元璋同志,這個同志當上了皇帝之后連宰相都不要了,所有的事情都親力親為,只有自己沒精力沒時間做的事才交給大臣們去干。

使用雙親委派模型有一個很明顯的好處,那就是 Java 類隨著它的類加載器一起具備了一種帶有優先級的層次關系,這對于保證 Java 程序的穩定運作很重要。

上文中曾提到,如果兩個類的加載器不同,即使兩個類來源于同一個字節碼文件,那這兩個類就必定不相等——雙親委派模型能夠保證同一個類最終會被特定的類加載器加載。

看完了這篇文章,相信你對Java的類加載機制是什么有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁乡县| 荣成市| 青州市| 潼南县| 德清县| 济源市| 宝丰县| 万州区| 阿坝县| 柳江县| 瑞昌市| 南靖县| 泰来县| 南皮县| 白河县| 青川县| 阳信县| 方山县| 靖边县| 南阳市| 金塔县| 团风县| 潼关县| 德兴市| 景洪市| 二手房| 安义县| 镇雄县| 五河县| 西峡县| 龙州县| 贺兰县| 军事| 长治县| 连云港市| 隆德县| 邯郸市| 天津市| 图木舒克市| 巩义市| 庄河市|