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

基于Java類的加載方式

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

類的生命周期

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

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

類加載的過程

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

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

一、加載(Loading)

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

類被載入JVM中,同一個類就不會再次被載入。

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

加載階段:

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

二、驗證(Verification)

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

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

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

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

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

需注意:

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

四、解析(Resolution)

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

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

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

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

五、 初始化

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

類加載器

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

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

雙親委派機制

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

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

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

雙親委派的作用

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

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

總結(jié)

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

相關(guān)文章

最新評論