JVM类加载(2)—连接
2、連接
連接就是將已經(jīng)加載到內(nèi)存中的類(lèi)的二進(jìn)制數(shù)據(jù)合并到Java虛擬機(jī)的運(yùn)行時(shí)環(huán)境中去,加載階段尚未完成,連接階段可能已經(jīng)開(kāi)始。連接階段包含驗(yàn)證、準(zhǔn)備、解析過(guò)程。
2.1、驗(yàn)證
驗(yàn)證.class文件正確性,驗(yàn)證階段大致會(huì)完成下面4個(gè)階段的檢驗(yàn)動(dòng)作
(1)、文件格式驗(yàn)證,這一階段主要驗(yàn)證字節(jié)流是否符合Class文件的格式規(guī)范,并且能被當(dāng)前版本的虛擬機(jī)處理。
(2)、元數(shù)據(jù)驗(yàn)證,第二階段是對(duì)字節(jié)碼描述信息進(jìn)行語(yǔ)義分析,以保證其描述的信息符合Java語(yǔ)言規(guī)范的要求,這個(gè)階段可能包含的驗(yàn)證點(diǎn)如下:
- 這個(gè)類(lèi)是否有父類(lèi)(除java.lang.Object類(lèi)之外,其他所有類(lèi)都應(yīng)該有父類(lèi))
- 這個(gè)類(lèi)的父類(lèi)是否繼承了不允許被繼承的類(lèi)(被final關(guān)鍵字修飾的類(lèi))
- 如果這個(gè)類(lèi)不是抽象類(lèi),是否實(shí)現(xiàn)了其父類(lèi)或接口之中要求實(shí)現(xiàn)的所有方法
- 類(lèi)中的變量、方法是否與父類(lèi)產(chǎn)生沖突(如覆蓋了父類(lèi)的final屬性,或者出現(xiàn)不符合規(guī)則的方法重載)等
第二階段主要目的是對(duì)類(lèi)的元數(shù)據(jù)信息進(jìn)行語(yǔ)義校驗(yàn),保證不存在不符合Java語(yǔ)言規(guī)范的元數(shù)據(jù)信息。
(3)、字節(jié)碼驗(yàn)證,第三階段是整個(gè)驗(yàn)證過(guò)程中最復(fù)雜的一個(gè)階段,主要目的是通過(guò)數(shù)據(jù)流和控制流分析,確定程序語(yǔ)義是合法的、符合邏輯的。在第二階段對(duì)元數(shù)據(jù)信息中的數(shù)據(jù)做完驗(yàn)證后,這個(gè)階段將對(duì)類(lèi)的方法體進(jìn)行校驗(yàn)分析,保證被校驗(yàn)類(lèi)的方法在運(yùn)行時(shí)不會(huì)做出危害JVM安全的事件,例如:
- 保證任意時(shí)刻操作數(shù)棧的數(shù)據(jù)類(lèi)型與指令代碼序列能配合工作,例如不會(huì)出現(xiàn)類(lèi)似這樣的情況:在操作棧放置了一個(gè)int型的數(shù)據(jù),使用時(shí)卻按照l(shuí)ong類(lèi)型加載入本地變量表中。
- 保證跳轉(zhuǎn)指令不會(huì)跳轉(zhuǎn)到方法體以為的字節(jié)碼指令上。
- 保證方法體中的類(lèi)型轉(zhuǎn)換是有效的。等
(4)、符號(hào)引用驗(yàn)證,最后一個(gè)階段的校驗(yàn)發(fā)生在虛擬機(jī)將符號(hào)引用轉(zhuǎn)化為直接引用的時(shí)候,這個(gè)轉(zhuǎn)化動(dòng)作將在連接的第三階段——解析階段中發(fā)生。符號(hào)引用驗(yàn)證可以看做是對(duì)類(lèi)自身以外(常量池中的各種符號(hào)引用)的信息進(jìn)行匹配性校驗(yàn),通常需要校驗(yàn)以下內(nèi)容:
- 符號(hào)引用中是否能通過(guò)字符串描述的全限定名找到對(duì)應(yīng)的類(lèi)
- 在指定類(lèi)中是否存在符合方法描述的字段描述符以及簡(jiǎn)單名稱(chēng)所描述的方法和字段
- 符號(hào)引用中的類(lèi)、字段、方法的訪問(wèn)性(private、default、protected、public)是否可被當(dāng)前類(lèi)訪問(wèn)。等
2.2、準(zhǔn)備
為類(lèi)的靜態(tài)變量分配內(nèi)存,并初始化默認(rèn)值,就像下面的這行代碼,在準(zhǔn)備階段JVM給int變量i分配內(nèi)存空間,并將i初始化為int型的默認(rèn)值,在準(zhǔn)備階段時(shí)i=0。
private static int i = 1;2.3、解析
解析階段JVM會(huì)把類(lèi)中的符號(hào)引用轉(zhuǎn)換為直接引用,如下代碼,Test類(lèi)中的showA()方法中調(diào)用了類(lèi)A的print()方法,這里a.print()就是符號(hào)引用,在解析階段會(huì)把a(bǔ).print()體會(huì)為方法區(qū)中一個(gè)指向A類(lèi)的print()方法在方法區(qū)中內(nèi)存地址的指針,而這個(gè)指針就是直接引用
1 class A{ 2 class A { 3 public void print() { 4 System.out.println("this is a"); 5 } 6 } 7 8 public class Test { 9 public void showA(A a) { 10 a.print(); 11 } 12 }?
符號(hào)引用(Symbolic References):符號(hào)引用是以一組符號(hào)來(lái)描述所引用的目標(biāo),符號(hào)可以是任何形式的字面量,只要使用時(shí)能無(wú)歧義的定位到目標(biāo)即可。符號(hào)引用于虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局無(wú)關(guān),引用的目標(biāo)不一定已經(jīng)加載到內(nèi)存中。各種虛擬機(jī)實(shí)現(xiàn)的內(nèi)存可以各不相同,但是它們所接受的符號(hào)引用必須是一致的,因?yàn)榉?hào)引用的字面量形式明確定義在Java虛擬機(jī)規(guī)范的Class文件格式中。
直接引用(Direct References):直接引用可以是指向目標(biāo)地址的指針、相對(duì)偏移量或是一個(gè)能間接定位到目標(biāo)的句柄。直接引用是和虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局是相關(guān)的,同一個(gè)符號(hào)引用在不同的虛擬機(jī)中翻譯出來(lái)的直接引用一般是不同的,如果有了直接引用,那引用目標(biāo)一定已經(jīng)在內(nèi)存中了。
轉(zhuǎn)載于:https://www.cnblogs.com/qiyexue/p/6822201.html
總結(jié)
以上是生活随笔為你收集整理的JVM类加载(2)—连接的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 将ListT集合用DataGridVie
- 下一篇: 如何突破你的“内在阻力”,让你渴望多年的