如何理解Java常見知識點中的分派機制,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
你所需要的網站建設服務,我們均能行業(yè)靠前的水平為你提供.標準是產品質量的保證,主要從事成都網站設計、成都網站建設、企業(yè)網站建設、手機網站開發(fā)、網頁設計、品牌網站制作、網頁制作、做網站、建網站。創(chuàng)新互聯(lián)擁有實力堅強的技術研發(fā)團隊及素養(yǎng)的視覺設計專才。
在Java中,符合“編譯時可知,運行時不可變”這個要求的方法主要是靜態(tài)方法和私有方法。這兩種方法都不能通過繼承或別的方法重寫,因此它們適合在類加載時進行解析。
Java虛擬機中有四種方法調用指令:
invokestatic:調用靜態(tài)方法。
invokespecial:調用實例構造器方法,私有方法和super。
invokeinterface:調用接口方法。
invokevirtual:調用以上指令不能調用的方法(虛方法)。
只要能被invokestatic和invokespecial指令調用的方法,都可以在解析階段確定唯一的調用版本,符合這個條件的有:靜態(tài)方法、私有方法、實例構造器、父類方法,他們在類加載的時候就會把符號引用解析為該方法的直接引用。這些方法被稱為非虛方法,反之其他方法稱為虛方法(final方法除外)。
雖然final方法是使用invokevirtual 指令來調用的,但是由于它無法被覆蓋,多態(tài)的選擇是唯一的,所以是一種非虛方法。
對于類字段的訪問也是采用靜態(tài)分派
People man = new Man()
靜態(tài)分派主要針對重載,方法調用時如何選擇。在上面的代碼中,People被稱為變量的引用類型,Man被稱為變量的實際類型。靜態(tài)類型是在編譯時可知的,而動態(tài)類型是在運行時可知的,編譯器不能知道一個變量的實際類型是什么。
編譯器在重載時候通過參數的靜態(tài)類型而不是實際類型作為判斷依據。并且靜態(tài)類型在編譯時是可知的,所以編譯器根據重載的參數的靜態(tài)類型進行方法選擇。
在某些情況下有多個重載,那編譯器如何選擇呢? 編譯器會選擇”最合適”的函數版本,那么怎么判斷”最合適“呢?越接近傳入參數的類型,越容易被調用。
動態(tài)分派主要針對重寫,使用invokevirtual指令調用。invokevirtual指令多態(tài)查找過程:
找到操作數棧頂的第一個元素所指向的對象的實際類型,記為C。
如果在類型C中找到與常量中的描述符合簡單名稱都相符的方法,則進行訪問權限校驗,如果通過則返回這個方法的直接引用,查找過程結束;如果權限校驗不通過,返回java.lang.IllegalAccessError異常。
否則,按照繼承關系從下往上一次對C的各個父類進行第2步的搜索和驗證過程。
如果始終沒有找到合適的方法,則拋出 java.lang.AbstractMethodError異常。
由于動態(tài)分派是非常繁瑣的動作,而且動態(tài)分派的方法版本選擇需要考慮運行時在類的方法元數據中搜索合適的目標方法,因此在虛擬機的實現中基于性能的考慮,在方法區(qū)中建立一個虛方法表(invokeinterface 有接口方法表),來提高性能。
虛方法表中存放各個方法的實際入口地址。如果某個方法在子類沒有重寫,那么子類的虛方法表里的入口和父類入口一致,如果子類重寫了這個方法,那么子類方法表中的地址會被替換為子類實現版本的入口地址。
關于如何理解Java常見知識點中的分派機制問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關知識。