欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Java類的加載方式

 更新時(shí)間:2023年07月13日 10:13:34   作者:Fluoxetine_Zero  
這篇文章主要介紹了基于Java類的加載方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

類的生命周期

當(dāng)java源代碼文件被javac編譯成class文件后,并不能直接運(yùn)行,而是需要經(jīng)過加載,連接和初始化這幾個(gè)階段后才能使用。

在使用完類或被銷毀后,JVM會(huì)將類卸載掉。

類加載的過程

類加載的過程需要經(jīng)過三個(gè)階段分別是:

  • 1.加載
  • 2.連接
  • 3.初始化,其中連接又可分為3個(gè)階段:驗(yàn)證,準(zhǔn)備,解析

一、加載(Loading)

由類加載器完成,類的class文件讀入內(nèi)存后,并將其保存到方法區(qū)內(nèi),然后就會(huì)創(chuàng)建一個(gè)java.lang.Class類型的對(duì)象。

類被載入JVM中,同一個(gè)類就不會(huì)再次被載入。

需要區(qū)分的是“加載”和“類加載”的區(qū)別,其中加載只是類加載的第一個(gè)環(huán)節(jié)。

加載階段:

  • 通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。
  • 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
  • 在內(nèi)存中生成一個(gè)代表此類的java.lang.Class的對(duì)象,作為訪問這個(gè)類的入口。

二、驗(yàn)證(Verification)

目的在于確保class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,保證被加載類的正確性,不會(huì)危害虛擬機(jī)自身安全,主要驗(yàn)證包括:

  • 驗(yàn)證文件格式:第一階段要驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范,并且能被當(dāng)前版本的虛擬機(jī)正確處理。
  • 元數(shù)據(jù)的驗(yàn)證:第二階段對(duì)字節(jié)碼描述的信息進(jìn)行語義分析,比如說驗(yàn)證這個(gè)類是不是有父類,類中的字段方法是不是和父類沖突等等,以保證其描述的信息符合Java語言的規(guī)范要求。
  • 字節(jié)碼驗(yàn)證:第三個(gè)階段主要是將對(duì)類的方法體(數(shù)據(jù)流和控制流)進(jìn)行驗(yàn)證分析。這個(gè)階段保證方法在運(yùn)行時(shí)不會(huì)出現(xiàn)危害虛擬機(jī)安全的行為語言規(guī)范
  • 符號(hào)引用驗(yàn)證:第四個(gè)階段符號(hào)引用驗(yàn)證可以看做是對(duì)類自身以外的信息進(jìn)行匹配性校驗(yàn),發(fā)生時(shí)機(jī)是虛擬機(jī)將符號(hào)引用轉(zhuǎn)換成直接引用時(shí)。

三、準(zhǔn)備(Preparation)

為類的靜態(tài)變量(static )分配內(nèi)存并為其賦零值(默認(rèn)值0、0.0、false、null等),但是不包含用final修飾的static,因?yàn)閒inal在編譯時(shí)就已經(jīng)分配了。

不會(huì)為實(shí)例變量分配初始值,類變量會(huì)分配在方法區(qū)中,而實(shí)例變量是會(huì)隨著對(duì)象一起分配到堆中。

需注意:

  • 這里僅只是給靜態(tài)變量賦值,而不是成員變量。
  • 在JDK8之前,類的元信息、常量池、靜態(tài)變量等都存儲(chǔ)在永久代這種具體實(shí)現(xiàn)中,而在JDK8及以后字符串常量池、靜態(tài)變量被移除“方法區(qū)”,轉(zhuǎn)移到了堆中而元信息,運(yùn)行時(shí)常量池這些依然保留在方法區(qū)內(nèi),但是具體的存儲(chǔ)方式改成了元空間。

四、解析(Resolution)

將常量池中的符號(hào)引用替換為直接引用(內(nèi)存地址)的過程, 主要包括四種類型引用的解析:類或接口的解析、 字段解析、方法解析、接口方法解析。

  • 符號(hào)引用:一個(gè)Java類被編譯成Class之后,如上圖,當(dāng)Test1中引用了Test2,那么在編譯階段,Test1是不知道Test2有沒有被編譯,也代表Test2一定沒有被加載,所以Test1肯定不知道Test2的實(shí)際地址。此時(shí)在Test1的class的文件中,將使用一個(gè)字符串來代表Test2的地址,這個(gè)字符串就被稱為是符號(hào)引用。
  • 直接引用:在運(yùn)行時(shí),如果Test1發(fā)生了類加載,到解析階段發(fā)現(xiàn)Test2還未被加載,這時(shí)將會(huì)觸發(fā)Test2的類加載,將Test2加載到虛擬機(jī)中,此時(shí)Test1中Test2的符號(hào)引用將會(huì)被替換為Test2的實(shí)際地址。

在解析階段,會(huì)將常量池中符號(hào)引用替換為直接引用。但是只是替換了部分。這一部分是包含,所有私有方法、靜態(tài)方法、構(gòu)造器及初始化方法都是采用靜態(tài)綁定機(jī)制,在編譯器階段就已經(jīng)指明了調(diào)用方法在常量池中的符號(hào)引用,JVM運(yùn)行的時(shí)候只需要進(jìn)行一次常量池解析即可。如果Test1調(diào)用的Test2是一個(gè)具體的實(shí)現(xiàn)類那么就稱為靜態(tài)解析,因?yàn)榻馕龅哪繕?biāo)類很明確。

那么假如上層Java代碼中使用了多態(tài),這里的Test2可能是一個(gè)抽象類或者是接口,那么Test2就可能有兩個(gè)具體的實(shí)現(xiàn)類Test3和Test4,這時(shí)會(huì)因?yàn)門est2的具體實(shí)現(xiàn)并不明確導(dǎo)致不知道使用哪個(gè)具體類的直接引用來進(jìn)行替換,所以這里就會(huì)一直等到運(yùn)行過程中發(fā)生了調(diào)用,JVM才會(huì)調(diào)用棧中將會(huì)得到的具體的類型信息,這個(gè)時(shí)候在進(jìn)行解析就能用明確的直接引用來替換符號(hào)引用,這時(shí)解析階段就會(huì)發(fā)生在初始化階段之后,這就是動(dòng)態(tài)解析 用它來實(shí)現(xiàn)了后期綁定。

五、 初始化

初始化,則是為標(biāo)記為常量值的字段賦值的過程。只對(duì)static修飾的變量或語句塊進(jìn)行初始化。 如果初始化一個(gè)類的時(shí)候,其父類尚未初始化,則優(yōu)先初始化其父類。 如果同時(shí)包含多個(gè)靜態(tài)變量和靜態(tài)初始化塊,則按照自上而下的順序依次執(zhí)行。

類加載器

Java中默認(rèn)提供的三種類加載器:

  • 啟動(dòng)類加載器 BootstrapClassLoader(根加載器): 加載Java_Home/jre/lib目錄下的核心API
  • 擴(kuò)展類加載器 ExtClassLoader: 負(fù)責(zé)加載Java_Home/jre/lib/ext目錄下的所有jar包;
  • 應(yīng)用類加載 AppClassLoader:繼承URLClassLoader。對(duì)應(yīng)加載的應(yīng)用程序classpath目錄下的所有jar和class等

雙親委派機(jī)制

當(dāng)一個(gè)類加載器收到類加載請(qǐng)求的時(shí)候,它首先不會(huì)自己去加載這個(gè)類的信息,而是把該請(qǐng)求委派給父類加載器,依次向上。

所以所有的類加載請(qǐng)求都會(huì)被委派到父類加載器中,只有當(dāng)父類加載器中無法加載到所需的類,子類加載器才會(huì)自己嘗試去加載該類。

如果當(dāng)前類加載器和所有父類加載器都無法加載該類時(shí),則會(huì)拋出ClassNotFoundException異常。

雙親委派的作用

1、防止重復(fù)加載同一個(gè).class,通過委托確認(rèn)是否加載,如已加載,無需重復(fù)加載,保證數(shù)據(jù)安全。

2、防止核心.class不能被篡改。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論