日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++ 类数组_《深入java虚拟机》读书笔记类加载

發(fā)布時間:2025/4/16 c/c++ 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ 类数组_《深入java虚拟机》读书笔记类加载 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

概述

類加載機(jī)制是指虛擬機(jī)將描述類的數(shù)據(jù)從Class文件中加載到內(nèi)存,并進(jìn)行數(shù)據(jù)驗(yàn)證、解析、初始化等過程,最后形成可以直接被虛擬機(jī)使用的java類型。在java語言中類的加載、鏈接、初始化等過程并不是在編譯時期完成,而是在運(yùn)行時期才進(jìn)行的,這樣做的好處在于可以為語言提供了動態(tài)擴(kuò)展的特性(可以在運(yùn)行期間動態(tài)接收二進(jìn)制的字節(jié)碼文件解析運(yùn)行),壞處在于增加了性能的開銷。

類加載過程

類在jvm中的整個生命周期包括:

加載(loading)-->驗(yàn)證(verification)-->準(zhǔn)備(preparation)-->解析(resolution)-->初始化(initialization)-->使用(using)-->卸載(unloading)

其中驗(yàn)證、準(zhǔn)備、解析并稱為鏈接階段。并且加載、驗(yàn)證、準(zhǔn)備、解析、初始化階段的開始時機(jī)是確定的,當(dāng)然這里不需要等待前一個完成才執(zhí)行后一個。而解析過程則不一定了,因?yàn)镴ava語言可能會存在運(yùn)行時動態(tài)解析。

加載

加載過程實(shí)際上就是通過二進(jìn)制字節(jié)流生成Class對象的過程,整個過程可以分為以下階段: 1. 通過類的全限定名來獲取定義該類二進(jìn)制字節(jié)流,這里的字節(jié)流并不要求一定是從Class文件獲取,可以從壓縮包(jar,war)、其他文件生成(jsp)、網(wǎng)絡(luò)、計算生成(proxy)等等途徑獲得。 2. 將這個字節(jié)流所表示的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)換為方法去的動態(tài)運(yùn)行時數(shù)據(jù)結(jié)構(gòu)。數(shù)據(jù)存儲格式由虛擬機(jī)自行實(shí)現(xiàn)。 3. 在內(nèi)存中實(shí)例化一個java.lang.Class對象,作為方法區(qū)中該類的數(shù)據(jù)訪問入口。在HotSpot虛擬機(jī)中,Class對象在JDK1.7前是存儲在方法區(qū)中,在JDK1.7之后Class實(shí)例存放在堆中。

在加載過程中的獲取二進(jìn)制字節(jié)流階段既可以使用JDK提供了類加載器進(jìn)行加載,也可以使用我們自定義的類加載器加載。但是如果是加載一個數(shù)組類就有些不一樣了。

數(shù)組類本身并不通過類加載器加載,其由虛擬機(jī)直接創(chuàng)建,但是數(shù)組中承載的對象還是由類加載器加載:

如果數(shù)組類承載的對象時引用類型那么就遞歸(數(shù)組可以嵌套)的調(diào)用加載過程對類進(jìn)行加載,同時該數(shù)組將在加載被承載對象的類加載器的類名稱空間中被標(biāo)識。如果數(shù)組中的內(nèi)容并不是引用類型(基本數(shù)據(jù)類型),那么Java虛擬機(jī)將會將該數(shù)組標(biāo)記為與引導(dǎo)類加載器關(guān)聯(lián)。

驗(yàn)證

驗(yàn)證是鏈接過程的開始,這一階段的目的是為了保證Class文件的字節(jié)流中包含的信息符合虛擬機(jī)的要求,并且不會危害虛擬機(jī)的安全。

在加載一節(jié)我們說過二進(jìn)制的字節(jié)流并不一定必須是通過java代碼編譯而來,統(tǒng)一通過多種形式,甚至可以直接使用十六進(jìn)制數(shù)據(jù)構(gòu)造。所以我們必須要對數(shù)據(jù)進(jìn)行驗(yàn)證,否則隨意的數(shù)據(jù)可能導(dǎo)致虛擬機(jī)崩潰。在java虛擬機(jī)規(guī)范中對數(shù)據(jù)的約束和規(guī)范規(guī)則較多,大致可以分為4種: 1. 文件格式驗(yàn)證:主要驗(yàn)證字節(jié)流是否符合Class文件規(guī)范以及能否被當(dāng)前版本的虛擬機(jī)處理,包括魔數(shù)驗(yàn)證,版本號等等。目的是為了保證輸入的字節(jié)流能夠正確的解析和存儲于方法區(qū)內(nèi),在格式上符合描述一個java類型信息的要求。通過驗(yàn)證后,會將字節(jié)流信息存儲于內(nèi)存中的方法區(qū)中。 2. 元數(shù)據(jù)驗(yàn)證:對字節(jié)碼描述的信息進(jìn)行語義分析,保證不存在不符合java語言規(guī)范的元數(shù)據(jù)。如該類是否有父類,父類是否繼承了不允許繼承的類等等。 3. 字節(jié)碼驗(yàn)證:通過數(shù)據(jù)流和控制流來確定程序語義是否是合法的、符合邏輯的。該階段是對類的方法體進(jìn)行校驗(yàn)。例如保證指令的跳轉(zhuǎn)不會跳到方法體外的字節(jié)碼指令上,保證類型轉(zhuǎn)換時有效地等等。但是即使通過了字節(jié)碼驗(yàn)證也并不能表示程序就是絕對無措的。因?yàn)槲覀兊臋z驗(yàn)程序的程序本身是可能有錯或不足的。 4. 符號引用驗(yàn)證:該驗(yàn)證是在解析階段進(jìn)行的(類加載的過程可能是相互交叉的)。符號引用驗(yàn)證的目的是為了確保解析動作能正常執(zhí)行。如果無法通過符號引用驗(yàn)證,像java.lang.NoSuchMethodError等都是在該階段拋出的。

需要注意的是該校驗(yàn)并不是每一次都需要的,假設(shè)我們的程序在測試環(huán)境下多次測試都是正常的,那么我們在生產(chǎn)環(huán)境下可以通過-Xverify:none參數(shù)來關(guān)閉大部分的驗(yàn)證措施,用以提高虛擬機(jī)的類加載時間。

準(zhǔn)備

準(zhǔn)備階段是正式為類變量分配內(nèi)存和設(shè)置類變量初始值的階段,這些變量所需的內(nèi)存都是你在方法區(qū)進(jìn)行分配。

需要注意的是這里分配內(nèi)存的僅僅是類變量(static)而不包括實(shí)例變量。實(shí)例變量內(nèi)存分配和賦初值是在對對象實(shí)例化階段進(jìn)行的。同時這里的賦初值也并不是設(shè)置我們在程序中定義好的值,而是零值,比如int類型的零值為0,應(yīng)用類型零值為null。

但是如果是constantValue(同時被final和static進(jìn)行修飾)的值則是在該階段進(jìn)行賦值的,其他類型正式賦值是在初始化階段進(jìn)行的。

解析

解析是虛擬機(jī)將常量池中的符號引用替換為直接引用的過程。解析主要的對類,接口,字段,類方法,接口方法,方法類型等符引用進(jìn)行。

  • 符號引用:符號引用以一組符號來描述所引用的目標(biāo),符號可以是任意形式的字面量,只要使用時能夠無歧義的定位到目標(biāo)即可。
  • 直接引用:直接引用可以是直接指向目標(biāo)的指針,相對偏移量或是一個能間接定位到目標(biāo)的句柄。

初始化

初始化過程實(shí)際上就是對變量賦值(不是賦初值)的過程。包含所有類變量的賦值以及靜態(tài)代碼語句塊的執(zhí)行代碼,包括對父類的初始化。

類加載器

在前面的加載過程中有說到“通過類的全限定名來獲取該類的二進(jìn)制字節(jié)碼流”,這一過程的實(shí)現(xiàn)就是通過類加載器完成的。

類與類加載器

對于任意的一個類,都需要由該類本身和加載該類的類加載器來確定其在Java虛擬機(jī)中的唯一性,每一個類加載器都有一個獨(dú)立的類名稱空間。這句話的意思就是要判斷兩個類是否一樣,不能僅僅比較兩個類是否通過同一個Class文件生成的,假如兩個類通過同一個Class文件生成但是各自加載他們的類加載器不一樣,那么這兩個類也是不相等的,在使用equals方法和instanceof關(guān)鍵字等時都遵循這個原則。

幾種類加載器

這里介紹幾種已經(jīng)內(nèi)置的類加載器(都是針對于HotSpot vm): - BootStrap ClassLoader(啟動類加載器):該類加載器負(fù)責(zé)加載/lib目錄和由-Xbootclasspath參數(shù)指定的路徑下的類庫。但是并不是說把任意類庫放在lib目錄下都會被加載,必須是虛擬機(jī)內(nèi)定義好的名字的類庫。同時在HotSpot VM中BootStrap ClassLoader是由C++實(shí)現(xiàn),所以在java程序中我們無法獲取到該類加載器的實(shí)例,如果我們自定義的類加載器中需要用到BootStrap ClassLoader的話可以直接使用null代替。 - Extension ClassLoader(擴(kuò)展類加載器):該類加載器負(fù)責(zé)加載/lib/ext目錄下或者由java.ext.dirs變量指定的路徑下的類庫,該類加載器我們可以直接使用。 - Application ClassLoader(應(yīng)用類加載器):該類加載器負(fù)責(zé)加載用戶路徑(ClassPath)下的類庫。該類加載器也是默認(rèn)的類加載器。

我們也可以繼承ClassLoader類并重寫findClass方法進(jìn)行自定義類加載器。

雙親委派模型(Parents Delegation Model)

上面介紹的不同類加載器之間也并不是各自獨(dú)立運(yùn)作的,其相互之間存在著一些關(guān)系。

像上圖這種層級關(guān)系被稱為雙親委派模型,雙親委派模型是如果一個類加載器收到類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器完成。每個類加載器都是如此,只有當(dāng)父加載器在自己的搜索范圍內(nèi)找不到指定的類時,子加載器才會嘗試自己去加載。實(shí)際上雙親委派模型的并不是指每一個類加載器都有兩個父加載器,parents是指可以有多個父加載器,當(dāng)然也可以只有一個。這里的翻譯有點(diǎn)怪怪的。

雙親委派模型的好處在于通過不同層次的類加載器加載的類先天的帶有一個層次關(guān)系,保證同一個類不會被多次加載,例如類java.lang.Object,它由啟動類加載器加載。雙親委派模型保證任何類加載器收到的對java.lang.Object的加載請求,最終都是委派給處于模型最頂端的啟動類加載器進(jìn)行加載,因此Object類在程序的各種類加載器環(huán)境中都是同一個類。

雙親委派模型的實(shí)現(xiàn):

protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {Class<?> c = findLoadedClass(name);//如果該類沒有被加載則通過類加載器加載//已經(jīng)被加載就返回if (c == null) {long t0 = System.nanoTime();try {//判斷父加載器是否為空 為空表示使用BootStrap ClassLoader加載if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {//父加載器無法加載該類 下面有當(dāng)前類加載器自己加載}if (c == null) {long t1 = System.nanoTime();c = findClass(name);// this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}

雙親委派模型并不是一個強(qiáng)制性的約束,我們的實(shí)現(xiàn)理論上可以不遵循該模型理論。如果有必要的話可能會對雙親委派模型進(jìn)行破壞(讓父類加載器主動將類加載行為交給子類進(jìn)行或者直接由當(dāng)前類加載器加載不交給父類),比如JNDI,OSGI等。

如何破壞雙親委托

在自定義類加載器中我們一般是繼承ClassLoader類并重寫findClass方法,這樣findClass方法會調(diào)用loadClass就實(shí)現(xiàn)了雙親委托模型(loadClass方法會自動的先去找父類加載器)。

如果要破壞雙親委托模型的話可以直接實(shí)現(xiàn)loadClass方法即可。

總結(jié)

以上是生活随笔為你收集整理的c++ 类数组_《深入java虚拟机》读书笔记类加载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。