日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

詳解Java 類的加載機制

瀏覽:81日期:2022-08-26 10:19:14

一、類的加載機制

虛擬機把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對數(shù)據(jù)進行校驗、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。

類的加載指的是將類的.class文件中的二進制數(shù)據(jù)讀入到內(nèi)存中,將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個java.lang.Class對象,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。類的加載的最終產(chǎn)品是位于堆區(qū)中的Class對象,Class對象封裝了類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu),并且向Java程序員提供了訪問方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)的接口。

詳解Java 類的加載機制

類加載器并不需要等到某個類被“首次主動使用”時再加載它,JVM規(guī)范允許類加載器在預料某個類將要被使用時就預先加載它,如果在預先加載的過程中遇到了.class文件缺失或存在錯誤,類加載器必須在程序首次主動使用該類時才報告錯誤(LinkageError錯誤)如果這個類一直沒有被程序主動使用,那么類加載器就不會報告錯誤

加載.class文件的方式

? 從本地系統(tǒng)中直接加載? 通過網(wǎng)絡下載.class文件,這種場景最典型的應用就是Applet? 從zip,jar等歸檔文件中加載.class文件? 從專有數(shù)據(jù)庫中提取.class文件? 將Java源文件動態(tài)編譯為.class文件

二、類的加載時機

類從被加載到虛擬機內(nèi)存中開始,直到卸載出內(nèi)存為止,它的整個生命周期包括了:加載、驗證、準備、解析、初始化、使用和卸載這7個階段。其中,驗證、準備和解析這三個部分統(tǒng)稱為連接(linking)。

詳解Java 類的加載機制

其中,加載、驗證、準備、初始化和卸載這五個階段的順序是確定的,類的加載過程必須按照這種順序按部就班的“開始”(僅僅指的是開始,而非執(zhí)行或者結(jié)束,因為這些階段通常都是互相交叉的混合進行,通常會在一個階段執(zhí)行的過程中調(diào)用或者激活另一個階段),而解析階段則不一定(它在某些情況下可以在初始化階段之后再開始,這是為了支持Java語言的運行時綁定(也稱為動態(tài)綁定或晚期綁定)。

三、類的加載過程

接下來詳細講解一下Java虛擬機中類加載的全過程,也就是加載、驗證、準備、解析和初始化這五個階段所執(zhí)行的具體動作。

3.1 加載

“加載”(Loading)階段是“類加載”(Class Loading)過程的第一個階段,在此階段,虛擬機需要完成以下三件事情:

1、 通過一個類的全限定名來獲取定義此類的二進制字節(jié)流。

2、 將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。

3、 在Java堆中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這些數(shù)據(jù)的訪問入口。

上面的第一步獲取二進制字節(jié)流,并沒有限定只能從編譯好的.class文件中獲取,也可以是zip包,jar,war,網(wǎng)絡流(Applet),運行時計算生成(如動態(tài)代理,通過反射在運行時動態(tài)生成代理類),其他文件(如jsp,因jsp最終會編譯成class),數(shù)據(jù)庫(用的場景較少)。

對于數(shù)組類的加載,和普通類的加載有所不同。數(shù)組類本身不通過類加載器加載,而是由虛擬機直接完成。但是數(shù)組類的元素類型(指數(shù)組類去除維度之后的類型,如String[] 數(shù)組的元素類型就是 String)是靠類加載器加載的。

加載階段完成之后,虛擬機就會把外部的二進制字節(jié)流(不論從何處獲取的)按照一定的數(shù)據(jù)格式存儲在運行時數(shù)據(jù)區(qū)中的方法區(qū)。然后在內(nèi)存中實例化一個java.lang.Class對象(Class這個對象比較特殊,它存放在方法區(qū)中而不是堆中),這個對象將作為程序訪問方法區(qū)中的這些數(shù)據(jù)的外部接口。

加載階段即可以使用系統(tǒng)提供的類加載器在完成,也可以由用戶自定義的類加載器來完成。加載階段與連接階段的部分內(nèi)容(如一部分字節(jié)碼文件格式驗證動作)是交叉進行的,加載階段尚未完成,連接階段可能已經(jīng)開始,但這些夾在加載階段之中進行的動作,仍然屬于連接階段的內(nèi)容,這兩個階段的開始時間仍然保持著固定的先后順序。

3.2 驗證

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

Java語言本身是相對安全的語言,使用Java編碼是無法做到如訪問數(shù)組邊界以外的數(shù)據(jù)、將一個對象轉(zhuǎn)型為它并未實現(xiàn)的類型等,如果這樣做了,編譯器將拒絕編譯。但是,Class文件并不一定是由Java源碼編譯而來,可以使用任何途徑,包括用十六進制編輯器(如UltraEdit)直接編寫。如果直接編寫了有害的“代碼”(字節(jié)流),而虛擬機在加載該Class時不進行檢查的話,就有可能危害到虛擬機或程序的安全。

不同的虛擬機,對類驗證的實現(xiàn)可能有所不同,但大致都會完成下面四個階段的驗證:文件格式驗證、元數(shù)據(jù)驗證、字節(jié)碼驗證和符號引用驗證。

1、文件格式驗證,是要驗證字節(jié)流是否符合Class文件格式的規(guī)范,并且能被當前版本的虛擬機處理。如驗證魔數(shù)是否0xCAFEBABE;主、次版本號是否正在當前虛擬機處理范圍之內(nèi);常量池的常量中是否有不被支持的常量類型……該驗證階段的主要目的是保證輸入的字節(jié)流能正確地解析并存儲于方法區(qū)中,經(jīng)過這個階段的驗證后,字節(jié)流才會進入內(nèi)存的方法區(qū)中存儲,所以后面的三個驗證階段都是基于方法區(qū)的存儲結(jié)構(gòu)進行的。

2、元數(shù)據(jù)驗證,是對字節(jié)碼描述的信息進行語義分析,以保證其描述的信息符合Java語言規(guī)范的要求。可能包括的驗證如:這個類是否有父類;這個類的父類是否繼承了不允許被繼承的類;如果這個類不是抽象類,是否實現(xiàn)了其父類或接口中要求實現(xiàn)的所有方法……

3、字節(jié)碼驗證,主要工作是進行數(shù)據(jù)流和控制流分析,保證被校驗類的方法在運行時不會做出危害虛擬機安全的行為。如果一個類方法體的字節(jié)碼沒有通過字節(jié)碼驗證,那肯定是有問題的;但如果一個方法體通過了字節(jié)碼驗證,也不能說明其一定就是安全的。

4、符號引用驗證,發(fā)生在虛擬機將符號引用轉(zhuǎn)化為直接引用的時候,這個轉(zhuǎn)化動作將在“解析階段”中發(fā)生。驗證符號引用中通過字符串描述的權(quán)限定名是否能找到對應的類;在指定類中是否存在符合方法字段的描述符及簡單名稱所描述的方法和字段;符號引用中的類、字段和方法的訪問性(private、protected、public、default)是否可被當前類訪問

驗證階段對于虛擬機的類加載機制來說,不一定是必要的階段。如果所運行的全部代碼確認是安全的,可以使用-Xverify:none參數(shù)來關閉大部分的類驗證措施,以縮短虛擬機類加載時間。

3.3 準備

準備階段是類變量分配內(nèi)存并設置初始值的階段。這里的類變量指的是被static修飾的變量,而不包括實例變量。類變量被分配到方法區(qū)中,而實例變量存放在堆中。

這里的初始值指的是數(shù)據(jù)類型的默認值,而不是代碼中所賦的值。例如

publicstaticintvalue = 1 ;

在準備階段之后,value值為0,而不是1。賦值為1的動作發(fā)生在初始化階段。

但是,也要特殊情況,如果變量被static 和 final同時修飾,則準備階段直接賦值為指定值。如

public finallystaticintvalue = 1 ;

在準備階段之后,value的值即為1.

各數(shù)據(jù)類型的初始默認值如下:

詳解Java 類的加載機制

3.4 解析

解析階段是將常量池中的符號引用轉(zhuǎn)換為直接引用的過程。那什么是符號引用和直接引用呢?

符號引用是用一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義的定位到目標即可(前面JVM的模型中,也提到了符號引用,它存在于常量池中,包括類和接口的全限定名、字段的名稱和描述符、方法的名稱和描述符)。看概念可能比較抽象,可以理解為它就是一個代號,就像你有一個大名,同時也有一個小名,但是不管怎么叫指代的都是你本人。

直接引用可以是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。

解析動作主要針對類或接口、字段、類方法、接口方法、方法屬性、方法句柄、調(diào)用點限定符7類符號引用。此處分別介紹一下前四種的解析過程。

1、類或接口的解析

如果類C不是數(shù)組類型,那么虛擬機會把類C直接傳給類加載器。如果類C是數(shù)組類型并且元素類型是對象(如String[]),那么先用類加載器加載元素類型(String類型),再由虛擬機創(chuàng)建代表此數(shù)組維度和元素的數(shù)組對象。判斷調(diào)用類是否有權(quán)限訪問被加載類,如果不允許的話,就拋出IllegalAccessError異常。

2、字段的解析

首先解析字段所屬的類或接口的符號引用。如果類中有字段的符號引用(字段的名稱和描述符)和目標字段相匹配,則返回這個字段的直接引用。如果沒有,則自下而上查找其實現(xiàn)的接口和父接口,若匹配到,則返回這個字段的直接引用。如果還沒有,就自下而上查找其繼承的父類,若匹配到,則返回這個字段的直接引用。否則,查找失敗,拋出NoSuchFieldError異常。最后如果查找成功的話,會判斷字段訪問權(quán)限,如果該字段不允許訪問,則拋出 IllegalAccessError異常。

3、類方法解析

類方法解析第一步同字段解析一樣,也需要先解析方法所屬的類或接口的符號引用。類方法和接口方法符號引用的常量類型是分開的。如果,在類方法中解析出來的是一個接口,則會拋出 IncompatibleClassChangeError 異常。如果在類中有方法的符號引用(方法的名稱和描述符)和目標方法相匹配,則返回這個方法的直接引用,查找結(jié)束。否則,在類的父類中遞歸查找,若找到則返回,查找結(jié)束。否則,查找它實現(xiàn)的接口和父接口,如果找到,說明此類是一個抽象類,拋出 AbstractMethodError異常。若都找不到,就拋出NoSuchMethodError 異常。最后,如果查找成功,會判斷此方法是否有訪問權(quán)限,若沒有,則拋出 IllegalAccessError異常。

4、接口方法的解析

首先解析方法所屬的類或接口的符號引用,和類方法解析同理,如果發(fā)現(xiàn)解析出來是一個類方法,則會拋出 IncompatibleClassChangeError 異常。如果所屬接口中匹配到目標方法,則返回此方法的直接引用。否則,在父接口中查找,若找到,則返回。否則,查找失敗,拋出 NoSuchMethodError 異常。由于接口的方法都是public的,所以不存在訪問權(quán)限的問題。

3.5 初始化

這是類加載的最后一步,到這才真正開始執(zhí)行Java代碼。在準備階段,已經(jīng)為類變量分配內(nèi)存,并賦值了默認值。在初始階段,則可以根據(jù)需要來賦值了。可以說,初始化階段是執(zhí)行類構(gòu)造器 < clinit > 方法的過程。

首先說下類構(gòu)造器 < clinit > 方法和實例構(gòu)造器 < init > 方法有什么區(qū)別。< clinit > 方法是在類加載的初始化階段執(zhí)行,是對靜態(tài)變量、靜態(tài)代碼塊進行的初始化。而< init > 方法是new一個對象,即調(diào)用類的 constructor方法時才會執(zhí)行,是對非靜態(tài)變量進行的初始化。

類構(gòu)造器方法有如下特點:

保證父類的 < clinit > 方法執(zhí)行完畢,再執(zhí)行子類的 < clinit > 方法。由于父類的 < clinit > 方法先執(zhí)行,所以父類的靜態(tài)代碼塊也優(yōu)于子類執(zhí)行。如果類中沒有靜態(tài)代碼塊,也沒有為變量賦值,則可以不生成 < clinit > 方法。執(zhí)行接口的 < clinit > 方法時,不需要先執(zhí)行父接口的 < clinit > 方法。只有父接口中定義的變量使用時,父接口才會初始化。另外,接口的實現(xiàn)類在初始化時也不執(zhí)行接口的 < clinit > 方法。虛擬機會保證在多線程環(huán)境下 < clinit > 方法能被正確的加鎖、同步。如果有多個線程同時請求加載一個類,那么只會有一個線程去執(zhí)行這個類的 < clinit > 方法,其他線程都會阻塞,直到方法執(zhí)行完畢。同時,其他線程也不會再去執(zhí)行 < clinit > 方法了。這就保證了同一個類加載器下,一個類只會初始化一次。(這也是為什么說餓漢式單例模式是線程安全的,因為類只會加載一次。)類的初始化時機:只有對類主動使用的時候才會觸發(fā)初始化,主動使用的場景如下:

使用new關鍵詞創(chuàng)建對象時,訪問某個類的靜態(tài)變量或給靜態(tài)變量賦值時,調(diào)用類的靜態(tài)方法時。反射調(diào)用時,會觸發(fā)類的初始化(如Class.forName())初始化一個類的時候,如其父類未初始化,則會先觸發(fā)父類的初始化。虛擬機啟動時,會先初始化主類(即包含main方法的類)。另外,也有些場景并不會觸發(fā)類的初始化:

通過子類調(diào)用父類的靜態(tài)變量,只會觸發(fā)父類的初始化,而不會觸發(fā)子類的初始化(因為,對于靜態(tài)變量,只有直接定義這個變量的類才會初始化)。通過數(shù)組來創(chuàng)建對象不會觸發(fā)此類的初始化。(如定義一個自定義的Person[] 數(shù)組,不會觸發(fā)Person類的初始化)通過調(diào)用靜態(tài)常量(即static final修飾的變量),并不會觸發(fā)此類的初始化。因為,在編譯階段,就已經(jīng)把final修飾的變量放到常量池中了,本質(zhì)上并沒有直接引用到定義常量的類,因此不會觸發(fā)類的初始化。

四、題目分析

上面很詳細的介紹了類的加載時機和類的加載過程,通過上面的理論來分析本文開門見上的題目

class SingleTon { private static SingleTon singleTon = new SingleTon(); public static int count1; public static int count2 = 0; private SingleTon() { count1++; count2++; } public static SingleTon getInstance() { return singleTon; }} public class Test { public static void main(String[] args) { SingleTon singleTon = SingleTon.getInstance(); System.out.println('count1=' + singleTon.count1); System.out.println('count2=' + singleTon.count2); }}

分析:

1、SingleTon singleTon = SingleTon.getInstance();調(diào)用了類的SingleTon調(diào)用了類的靜態(tài)方法,觸發(fā)類的初始化2、類加載的時候在準備過程中為類的靜態(tài)變量分配內(nèi)存并初始化默認值 singleton=null count1=0,count2=03、類初始化化,為類的靜態(tài)變量賦值和執(zhí)行靜態(tài)代碼快。singleton賦值為new SingleTon()調(diào)用類的構(gòu)造方法4、調(diào)用類的構(gòu)造方法后count=1;count2=15、繼續(xù)為count1與count2賦值,此時count1沒有賦值操作,所有count1為1,但是count2執(zhí)行賦值操作就變?yōu)?

參考:

《深入理解Java虛擬機:JVM高級特性與最佳實踐》

以上就是詳解Java 類的加載機制的詳細內(nèi)容,更多關于Java 類的加載的資料請關注好吧啦網(wǎng)其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
天堂va在线高清一区| 五月天激情综合网| 欧美一区二区三区激情视频 | 亚洲精品乱码| 在线精品国产亚洲| 日韩精品一级中文字幕精品视频免费观看 | 97精品久久| 国产精品毛片aⅴ一区二区三区| 欧美日韩a区| 国产精品115| 亚洲美女久久精品| 久久在线电影| 久久av在线| 亚洲免费影视| 最新国产精品视频| 欧美日韩午夜| 国模大尺度视频一区二区| 在线中文字幕播放| 99免费精品| 视频一区中文字幕国产| 日韩av二区在线播放| 精品中文在线| 免费视频国产一区| 婷婷视频一区二区三区| 国产精品白丝av嫩草影院| 日韩欧美一区二区三区在线视频| 性欧美69xoxoxoxo| 亚洲三级av| 国产精品欧美在线观看| 黑人精品一区| 亚洲女人av| 国产女人18毛片水真多18精品| 欧美激情三区| 日韩精品看片| 中文字幕一区二区精品区| 国产精品香蕉| 99精品小视频| 天堂va欧美ⅴa亚洲va一国产| 欧美91在线|欧美| 在线日韩欧美| 日韩手机在线| 日韩理论片av| 亚洲人成精品久久久| 国产精品亚洲综合久久| 中文一区一区三区高中清不卡免费| 91精品福利| 国产探花在线精品一区二区| 日本精品影院| 蜜臀av亚洲一区中文字幕| 国产免费播放一区二区| 欧美日韩一区二区综合| 日韩欧美三区| bbw在线视频| 一区二区三区国产盗摄| 精品国产a一区二区三区v免费| 一本一道久久a久久精品蜜桃| 国产欧美在线| 久久精品国产亚洲夜色av网站| 免费在线欧美视频| 精品久久99| 亚洲欧美一级| 美女网站视频一区| 国产毛片精品| 亚洲在线成人| 日本久久黄色| 日韩成人午夜精品| 日韩网站中文字幕| 国产欧美一区二区三区国产幕精品| av在线日韩| 国产高清精品二区| 亚洲综合福利| 精品丝袜久久| 久久国产日韩| 欧美特黄一区| 午夜在线播放视频欧美| 成人台湾亚洲精品一区二区| 亚洲人成毛片在线播放女女| 国产中文字幕一区二区三区| 亚洲精品九九| 在线国产一区| 日韩av片子| 久久精品xxxxx| 激情欧美国产欧美| 久久精品国产久精国产爱| 一区二区三区四区日韩| 91精品推荐| 福利视频一区| 国产精品一区二区三区四区在线观看 | 国产欧美一区二区色老头| 久久高清免费| 麻豆国产精品一区二区三区| 热久久久久久久| 久久亚洲国产| 久久精品国产999大香线蕉 | 老司机久久99久久精品播放免费| 麻豆精品一区二区综合av| 亚洲综合精品| 在线成人直播| 久久国产日韩| 麻豆国产91在线播放| 日韩一区二区三区免费视频| 亚洲一区二区三区四区五区午夜 | 国产美女久久| 麻豆精品网站| 国产综合色区在线观看| 久久成人高清| 亚洲欧美日本国产| 91成人精品视频| 久久天堂av| 成人一区而且| 国产精品.xx视频.xxtv| 97久久超碰| 婷婷成人av| 麻豆9191精品国产| 精品在线99| 久久久久久美女精品| 激情综合婷婷| 国产精品红桃| 国产精品天堂蜜av在线播放| 日本欧美大码aⅴ在线播放| 三级欧美在线一区| 在线日韩一区| 香蕉成人av| 三上悠亚国产精品一区二区三区| 岛国av免费在线观看| 福利一区在线| 国产欧美日韩免费观看| 亚洲精品高潮| 日韩有码av| 青青草伊人久久| 亚洲aa在线| 亚洲精品国产日韩| 丝袜诱惑制服诱惑色一区在线观看| 亚洲午夜视频| 在线中文字幕播放| 美女一区网站| 免费高潮视频95在线观看网站| 国产精品久久观看| 电影天堂国产精品| 欧美午夜精彩| 在线亚洲精品| 日韩精品一二三| 一区二区日韩免费看| 亚洲婷婷丁香| 欧美日韩视频免费看| 91精品福利观看| 国产精品亲子伦av一区二区三区| 美女高潮久久久| 国产精品久久久久久久免费观看 | 日韩高清欧美| 韩国精品主播一区二区在线观看| 日韩国产网站| 亚洲欧美久久| 日本伊人久久| 麻豆精品视频在线观看视频| 国产一区二区三区精品在线观看| 免费污视频在线一区| 午夜精品亚洲| 日韩欧乱色一区二区三区在线| 国产精品白浆| 亚洲三级欧美| 久久久久久久久久久9不雅视频| 国产在线成人| 亚洲精品麻豆| 成人在线黄色| 在线综合亚洲| 日本麻豆一区二区三区视频| 欧美国产中文高清| 久久精品中文| 天堂av在线一区| 午夜精品福利影院| 国内在线观看一区二区三区| 波多野结衣一区| 日韩欧美中文在线观看| 福利一区在线| 久热re这里精品视频在线6| 日本a口亚洲| 伊人网在线播放| 日韩专区一卡二卡| 国产精品免费不| 久久免费高清| 日韩一区二区三区四区五区| 国产成人精选| 黄页网站一区| 国产精久久一区二区| 99久久亚洲精品| 日韩精品视频中文字幕| 久久久久久夜| 亚洲网址在线观看| 精品三级久久久| 免费看日韩精品| 国产精品亚洲片在线播放| 日韩一区二区三区免费播放| 久久亚洲风情| 国产精品国产一区| 视频在线观看91| 色在线中文字幕| 青青草视频一区| 偷拍欧美精品| 狠狠久久伊人中文字幕|