Java接口回調(diào)的本質(zhì)詳解
本質(zhì)是JVM指令invokevirtual它涉及到了多態(tài)的特性,使用 virtual dispatch 做方法調(diào)用
virtual dispatch 機(jī)制會(huì)首先從 receiver(被調(diào)用方法的對(duì)象的實(shí)際類型)的類的實(shí)現(xiàn)中查找對(duì)應(yīng)的方法,如果沒找到,則去父類查找,直到找到函數(shù)并實(shí)現(xiàn)調(diào)用,而不是依賴于引用的類型。
我們知道了接口回調(diào)的本質(zhì)是多態(tài),多態(tài)的本質(zhì)是JVM的invokevirtual指令,那么我們就不用拘泥于接口和抽象類或者繼承關(guān)系這種概念了,我們直接寫一個(gè)用普通類實(shí)現(xiàn)的回調(diào)然后再分析它:
public class TestA{ public void A(){ System.out.println("A"); } } public class TestC { public void C(TestA A){ System.out.println("ccc1"); A.A(); System.out.println("ccc2"); } } public class JavaTest { public static void main(String[] args) { TestC testC = new TestC(); testC.C(new TestA(){ @Override public void A() { System.out.println("fsf"); } }); } }
執(zhí)行結(jié)果:
如果是invokespecial指令:
public class TestA { private void A(){ System.out.println("A"); } } public class TestC { public void C(TestA A){ System.out.println("ccc1"); //注意這里不能用 A.getClass,getClass方法也是用invokevirtual指令調(diào)用的 Class aClass = TestA.class; try { Method method = aClass.getDeclaredMethod("A"); method.setAccessible(true); method.invoke(A); } catch (Exception e) { e.printStackTrace(); } System.out.println("ccc2"); } } public class Test{ public static void main(String[] args) { TestC testC = new TestC(); testC.C(new TestA(){ private void A() { System.out.println("fsf"); } }); } }
JVM在調(diào)用private方法的時(shí)候使用的是invokespecial指令,但是我們不能直接在外部調(diào)用私有方法所以就寫了個(gè)反射來調(diào)用,執(zhí)行結(jié)果:
如果有因?yàn)槭遣皇且驗(yàn)榉瓷鋵?dǎo)致的,我們排除一下反射:
public class TestA{ public void A() { System.out.println("A"); } } public class TestC { public void C(TestA A){ System.out.println("ccc1"); Class aClass = TestA.class; try { Method method = aClass.getDeclaredMethod("A"); method.setAccessible(true); method.invoke(A); } catch (Exception e) { e.printStackTrace(); } System.out.println("ccc2"); } } public class Test{ public static void main(String[] args) { TestC testC = new TestC(); testC.C(new TestA(){ public void A() { System.out.println("fsf"); } }); } }
執(zhí)行結(jié)果:
使用反射和不使用反射的結(jié)果一致可以排除反射的干擾
到此這篇關(guān)于Java接口回調(diào)的本質(zhì)詳解的文章就介紹到這了,更多相關(guān)Java接口回調(diào)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中的日期時(shí)間類實(shí)例詳解(Date、Calendar、DateFormat)
在JDK1.0中,Date類是唯一的一個(gè)代表時(shí)間的類,但是由于Date類不便于實(shí)現(xiàn)國(guó)際化,所以從JDK1.1版本開始,推薦使用Calendar類進(jìn)行時(shí)間和日期處理,這篇文章主要介紹了Java中的日期時(shí)間類詳解(Date、Calendar、DateFormat),需要的朋友可以參考下2023-11-11MyBatis動(dòng)態(tài)Sql之if標(biāo)簽的用法詳解
這篇文章主要介紹了MyBatis動(dòng)態(tài)Sql之if標(biāo)簽的用法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-07-07解決springboot application.properties server.port配置問題
這篇文章主要介紹了解決springboot application.properties server.port配置問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Disconf實(shí)現(xiàn)分布式配置管理的原理與設(shè)計(jì)
這篇文章主要為大家介紹了Disconf實(shí)現(xiàn)分布式配置管理的原理與設(shè)計(jì)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03Java中BigDecimal的加減乘除、比較大小與使用注意事項(xiàng)
對(duì)于不需要任何準(zhǔn)確計(jì)算精度的數(shù)字可以直接使用float或double,但是如果需要精確計(jì)算的結(jié)果,則必須使用BigDecimal類,而且使用BigDecimal類也可以進(jìn)行大數(shù)的操作,下面這篇文章給大家介紹了Java中BigDecimal的加減乘除、比較大小與使用注意事項(xiàng),需要的朋友可以參考下。2017-11-11Springboot整合Swagger2后訪問swagger-ui.html 404報(bào)錯(cuò)問題解決方案
這篇文章主要介紹了Springboot整合Swagger2后訪問swagger-ui.html 404報(bào)錯(cuò),本文給大家分享兩種解決方案,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06IDEA導(dǎo)入JDBC驅(qū)動(dòng)的jar包步驟詳解
JDBC是一種底層的API,是連接數(shù)據(jù)庫和Java應(yīng)用程序的紐帶,因此我們?cè)谠L問數(shù)據(jù)庫時(shí)需要在業(yè)務(wù)邏輯層中嵌入SQL語句,這篇文章主要介紹了IDEA導(dǎo)入JDBC驅(qū)動(dòng)的jar包,需要的朋友可以參考下2023-07-07XSS攻擊以及java應(yīng)對(duì)xss攻擊的解決方案
XSS是跨站腳本攻擊Cross Site Scripting的縮寫,為了和層疊樣式表CSS加以區(qū)分,因此將跨站腳本攻擊縮寫為XSS,這篇文章主要給大家介紹了關(guān)于XSS攻擊以及java應(yīng)對(duì)xss攻擊的解決方案,需要的朋友可以參考下2024-02-02