|
Java為什么能運行期間動態(tài)確定調(diào)用方法?是怎么實現(xiàn)的呢。 在繼承關(guān)系中,運行時動態(tài)確定要調(diào)用的方法的版本,是根據(jù)字節(jié)碼指令invokevirtual來完成的。需要從這個指令的"多態(tài)查找"過程說起。 invokevirtual的運行過程如下: 第一、找到操作數(shù)棧頂元素的實際類型,記做C, 第二、如果在才、C中找到與常量中描述符和簡單名稱都相同的方法,則進行權(quán)限校驗,如果通過,則返回這個方法的直接引用,查找過程結(jié)束。權(quán)限校驗不通過則返回java的illegalaccesserror。 第三、如果經(jīng)過第二步?jīng)]找到也沒拋出異常,則按照繼承關(guān)系在父類中查找。 第四、如果始終沒有找到,則跑出abstractmethoderror。 由于invokevirtual指令在執(zhí)行的第一步就是確定接收者的實際類型,所以調(diào)用的時候,針對不同的調(diào)用者(即所說的方法接收者)會把常量池中的類方法解析到不同的直接引用上,這個過程就是java語言“覆蓋”父類方法的本質(zhì),也就是“重寫”的本質(zhì)。 [java] view plaincopy
上面代碼a和b分別會調(diào)用兩個子類的test函數(shù),可以作為例子參考。 ------------------------------------------------------------------------------------------------------- 上面的全部都是在說子類重寫父類的方法,那么如果在同一個類中重載一個函數(shù),那么是怎么確定調(diào)用版本的呢? 這需要從“靜態(tài)類型”和“動態(tài)類型”說起。 比如: 父類 a=new 子類, 在上面,父類是靜態(tài)類型,子類是動態(tài)類型,【因為子類是這個對象的實際類型,稱之為動態(tài)類型】 如果在一個類 [java] view plaincopy
代碼如上。調(diào)用的時候,如果這么調(diào)用: 父類 a=new 父類 父類 b=new 子類1 父類 c=new 子類2 new TR().test(a); new TR().test(b); new TR().test(c); 那么這三句話會分別輸出什么呢? 這個有可能會有人回答錯誤。 會輸出三個father! 這是因為,虛擬機(準(zhǔn)確的說是編譯器)在重載時候是通過靜態(tài)類型而不是動態(tài)類型來確定調(diào)用方法的版本的。所以三個調(diào)用語句都會選擇void test(父類 a)作為調(diào)用函數(shù)。 |
|
|