😉😉 歡迎加入我們的學習交流群呀:
??1:這是孫哥suns給大家的福利!
??2:我們免費分享Netty、Dubbo、k8s、Mybatis、Spring...應用和源碼級別的視頻資料
🥭🥭3:QQ群:583783824 ? 📚📚 ?工作微信:BigTreeJava 拉你進微信群,免費領取!
🍎🍎4:本文章內容出自上述:Spring應用課程!💞💞
💞💞5:以上內容,進群免費領取呦~ 💞💞💞💞
知識回顧
? ? ? ? 因為方法的重寫的出現的,導致我們出現了虛方法這種調用方式。之前我們提到的靜態方法、私有方法、final方法、實例構造器、父類方法都是非虛方法,是因為從這個角度來講,是不存在方法的重寫的,你仔細品位一下,確實是這么回事的。
一:方法的重寫的本質
1:本質介紹
? ? ? ? 第一步:當我們去調用一個對象的方法的時候,首先會將這個對象壓入操作數棧,經過invokeVurtual字節碼指令去嘗試調用方法。此時,當前被調用方法的對象位于操作數棧的棧頂,然后這個對象的方法類型被記作Type
? ? ? ? 第二步:如果在類型 Type中找到與常量中的描述符合、簡單名稱都相符的方法,則進行訪問權限校驗,如果通過也就是有權限,則返回這個方法的直接引用,查找過程結束。如果不通過,則返回java.lang.IllegalAccessError 異常,這是一個非法訪問的異常。
? ? ? ? 第三步:否則,按照繼承關系從下往上依次對Type的各個父類進行第 2 步的搜索和驗證過程
? ? ? ? 第四步:如果始終沒有找到合適的方法,則拋出 java.lang.AbstractMethodError異常。
2:IllegalAccessError介紹:
????????程序試圖訪問或修改一個屬性或調用一個方法,這個屬性或方法,你沒有權限訪問。一般的,這個會引起編譯器異常,換句話說,這個大概率發生在編譯階段。這個錯誤如果發生在運行時,就說明一個類發生了不兼容的改變。
? ? ? ? 舉個極端例子去理解這個事。本來我們程序線上玩的特別好,程序跑的很歡快。有個同學,修改bug的時候,順手把某個方法的修飾符public給去掉了(修改了方法適用范圍),服務啟動后,那么其他類在之前調用這個方法的時候沒有任何問題,但是真正運行的時候可能就完蛋了,這個異常就爆出來了。
二:虛方法表
1:虛方法表概念
????????在面向對象的編程中,會很頻繁的使用到動態分派也就是invokeVurtual字節碼指令。
????????如果在每次動態分派的過程中都要重新在類的方法元數據中搜索合適的目標的話就可能影響到執行效率。因此,為了提高性能,JVM采用在類的方法區建立一個虛方法表(virtual method table) (非虛方法不會出現在表中)來實現。使用索引表來代替查找。也就是說,現在查表就行,不一層一層往上找了。
????????每個類中都有一個虛方法表,表中存放著各個方法的實際入口。
2:虛方法表創建時機
????????那么虛方法表什么時候被創建?虛方法表會在類加載的鏈接階段被創建并開始初始化,類的變量初始值準備完成之后,JVM會把該類的方法表也初始化完畢。
? ? ? ? 我們當時講類加載過程中的鏈接這個階段的時候,其中解析的部分講的不是特別的透徹,因為這個回合我們后邊也就是現在有一些想通的內容。解析階段會將常量池中的符號應用轉換為直接引用。這個符號就包括類的符號、方法的符號等等。
(一):例子一
? ? ? ? 左右兩側是父類和子類在類中維護的兩個虛方法表,表中藍色部分二者都沒重寫,都繼承自Object。子類中也直接把這些方法存到了虛方法表中,找的時候直接從索引表中可以找到Object的方法來使用需要通過父類在后在找到Object中去尋找方法。
? ? ? ? 然后,二者都重寫了hard開頭的兩個方法,所以箭頭指向了他們自己。
(二):例子二
? ? ? ? 繼承關系圖:
? ? ? ? Java代碼編寫:
interface Friendly{void sayHello();void sayGoodBye();
}class Dog{public void sayHello(){}public String toString(){return "Dog";}
}class Cat implements Friendly{public void eat(){}public void sayHello(){}public void sayGoodBye() {}public void finalize(){}
}class CockerSpaniel extends Dog implements Friendly{public void sayHello() {super.sayHello();}public void sayGoodBye() {}
}
public class VirtualMethodTable {
}
? ? ? ? ?Dog虛方法表示意圖:
?
? ? ? ? Dog這個虛方法表重寫sayHello和toString,所以這兩個方法指向自己,其他的虛方法指向父類。?虛方法就不需要一層一層向上判斷了。
????????CockerSpaniel示意圖:
? ? ? ? Cat的示意圖:
3:虛方法表出現意義
? ? ? ? 他的出現是因為因為方法的重寫,重寫導致invokeVirtual尋找方法的時候一層一層向上找,會影響方法執行的效率,JVM基于虛方法表做了調整。簡化尋找過程,提升效率。