真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java的類加載機(jī)制是什么

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

站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到長(zhǎng)清網(wǎng)站設(shè)計(jì)與長(zhǎng)清網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、網(wǎng)頁(yè)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋長(zhǎng)清地區(qū)。

01、字節(jié)碼

在聊 Java 類加載機(jī)制之前,需要先了解一下 Java 字節(jié)碼,因?yàn)樗皖惣虞d機(jī)制息息相關(guān)。

計(jì)算機(jī)只認(rèn)識(shí) 0 和 1,所以任何語(yǔ)言編寫(xiě)的程序都需要編譯成機(jī)器碼才能被計(jì)算機(jī)理解,然后執(zhí)行,Java 也不例外。

Java 在誕生的時(shí)候喊出了一個(gè)非常牛逼的口號(hào):“Write Once, Run Anywhere”,為了達(dá)成這個(gè)目的,Sun 公司發(fā)布了許多可以在不同平臺(tái)(Windows、Linux)上運(yùn)行的 Java 虛擬機(jī)(JVM)——負(fù)責(zé)載入和執(zhí)行 Java 編譯后的字節(jié)碼。

Java的類加載機(jī)制是什么

到底 Java 字節(jié)碼是什么樣子,我們借助一段簡(jiǎn)單的代碼來(lái)看一看。

源碼如下:

package com.cmower.java_demo;

public class Test {

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

}

代碼編譯通過(guò)后,通過(guò) xxd Test.class 命令查看一下這個(gè)字節(jié)碼文件。

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  .....()V..
00000050: 0443 6f64 650a 0003 0009 0c00 0500 0601  .Code...........
00000060: 000f 4c69 6e65 4e75 6d62 6572 5461 626c  ..LineNumberTabl

感覺(jué)有點(diǎn)懵逼,對(duì)不對(duì)?

懵就對(duì)了。

這段字節(jié)碼中的 cafe babe 被稱為“魔數(shù)”,是 JVM 識(shí)別 .class 文件的標(biāo)志。文件格式的定制者可以自由選擇魔數(shù)值(只要沒(méi)用過(guò)),比如說(shuō) .png 文件的魔數(shù)是 8950 4e47。

至于其他內(nèi)容嘛,可以選擇忘記了。

02、類加載過(guò)程

了解了 Java 字節(jié)碼后,我們來(lái)聊聊 Java 的類加載過(guò)程。

Java 的類加載過(guò)程可以分為 5 個(gè)階段:載入、驗(yàn)證、準(zhǔn)備、解析和初始化。這 5 個(gè)階段一般是順序發(fā)生的,但在動(dòng)態(tài)綁定的情況下,解析階段發(fā)生在初始化階段之后。

1)Loading(載入)

JVM 在該階段的主要目的是將字節(jié)碼從不同的數(shù)據(jù)源(可能是 class 文件、也可能是 jar 包,甚至網(wǎng)絡(luò))轉(zhuǎn)化為二進(jìn)制字節(jié)流加載到內(nèi)存中,并生成一個(gè)代表該類的 java.lang.Class 對(duì)象。

2)Verification(驗(yàn)證)

JVM 會(huì)在該階段對(duì)二進(jìn)制字節(jié)流進(jìn)行校驗(yàn),只有符合 JVM 字節(jié)碼規(guī)范的才能被 JVM 正確執(zhí)行。該階段是保證 JVM 安全的重要屏障,下面是一些主要的檢查。

確保二進(jìn)制字節(jié)流格式符合預(yù)期(比如說(shuō)是否以 cafe bene 開(kāi)頭)。

是否所有方法都遵守訪問(wèn)控制關(guān)鍵字的限定。

方法調(diào)用的參數(shù)個(gè)數(shù)和類型是否正確。

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

檢查變量是否被賦予恰當(dāng)類型的值。

3)Preparation(準(zhǔn)備)

JVM 會(huì)在該階段對(duì)類變量(也稱為靜態(tài)變量,static 關(guān)鍵字修飾的)分配內(nèi)存并初始化(對(duì)應(yīng)數(shù)據(jù)類型的默認(rèn)初始值,如 0、0L、null、false 等)。

也就是說(shuō),假如有這樣一段代碼:

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

chenmo 不會(huì)被分配內(nèi)存,而 wanger 會(huì);但 wanger 的初始值不是“王二”而是 null。

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

4)Resolution(解析)

該階段將常量池中的符號(hào)引用轉(zhuǎn)化為直接引用。

what?符號(hào)引用,直接引用?

符號(hào)引用以一組符號(hào)(任何形式的字面量,只要在使用時(shí)能夠無(wú)歧義的定位到目標(biāo)即可)來(lái)描述所引用的目標(biāo)。

在編譯時(shí),Java 類并不知道所引用的類的實(shí)際地址,因此只能使用符號(hào)引用來(lái)代替。比如 com.Wanger 類引用了 com.Chenmo 類,編譯時(shí) Wanger 類并不知道 Chenmo 類的實(shí)際內(nèi)存地址,因此只能使用符號(hào) com.Chenmo。

直接引用通過(guò)對(duì)符號(hào)引用進(jìn)行解析,找到引用的實(shí)際內(nèi)存地址。

5)Initialization(初始化)

該階段是類加載過(guò)程的最后一步。在準(zhǔn)備階段,類變量已經(jīng)被賦過(guò)默認(rèn)初始值,而在初始化階段,類變量將被賦值為代碼期望賦的值。換句話說(shuō),初始化階段是執(zhí)行類構(gòu)造器方法的過(guò)程。

oh,no,上面這段話說(shuō)得很抽象,不好理解,對(duì)不對(duì),我來(lái)舉個(gè)例子。

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

上面這段代碼使用了 new 關(guān)鍵字來(lái)實(shí)例化一個(gè)字符串對(duì)象,那么這時(shí)候,就會(huì)調(diào)用 String 類的構(gòu)造方法對(duì) cmower 進(jìn)行實(shí)例化。

03、類加載器

聊完類加載過(guò)程,就不得不聊聊類加載器。

一般來(lái)說(shuō),Java 程序員并不需要直接同類加載器進(jìn)行交互。JVM 默認(rèn)的行為就已經(jīng)足夠滿足大多數(shù)情況的需求了。不過(guò),如果遇到了需要和類加載器進(jìn)行交互的情況,而對(duì)類加載器的機(jī)制又不是很了解的話,就不得不花大量的時(shí)間去調(diào)試

ClassNotFoundException 和 NoClassDefFoundError 等異常。

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

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

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

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

3)應(yīng)用類加載器(Application or App Clas-Loader),根據(jù)程序的類路徑(classpath)來(lái)加載 Java 類。

來(lái)來(lái)來(lái),通過(guò)一段簡(jiǎn)單的代碼了解下。

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();
		}
	}

}

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

這段代碼的輸出結(jié)果如下:

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

第一行輸出為 Test 的類加載器,即應(yīng)用類加載器,它是 sun.misc.Launcher$AppClassLoader 類的實(shí)例;第二行輸出為擴(kuò)展類加載器,是 sun.misc.Launcher$ExtClassLoader 類的實(shí)例。那啟動(dòng)類加載器呢?

按理說(shuō),擴(kuò)展類加載器的上層類加載器是啟動(dòng)類加載器,但在我這個(gè)版本的 JDK 中, 擴(kuò)展類加載器的 getParent() 返回 null。所以沒(méi)有輸出。

04、雙親委派模型

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

Java的類加載機(jī)制是什么

這種層次關(guān)系被稱作為雙親委派模型:如果一個(gè)類加載器收到了加載類的請(qǐng)求,它會(huì)先把請(qǐng)求委托給上層加載器去完成,上層加載器又會(huì)委托上上層加載器,一直到最頂層的類加載器;如果上層加載器無(wú)法完成類的加載工作時(shí),當(dāng)前類加載器才會(huì)嘗試自己去加載這個(gè)類。

PS:雙親委派模型突然讓我聯(lián)想到朱元璋同志,這個(gè)同志當(dāng)上了皇帝之后連宰相都不要了,所有的事情都親力親為,只有自己沒(méi)精力沒(méi)時(shí)間做的事才交給大臣們?nèi)ジ伞?/p>

使用雙親委派模型有一個(gè)很明顯的好處,那就是 Java 類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系,這對(duì)于保證 Java 程序的穩(wěn)定運(yùn)作很重要。

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

看完了這篇文章,相信你對(duì)Java的類加載機(jī)制是什么有了一定的了解,想了解更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!


當(dāng)前標(biāo)題:Java的類加載機(jī)制是什么
鏈接地址:http://weahome.cn/article/jhscsp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部