Java接口回調的本質詳解
本質是JVM指令invokevirtual它涉及到了多態(tài)的特性,使用 virtual dispatch 做方法調用
virtual dispatch 機制會首先從 receiver(被調用方法的對象的實際類型)的類的實現(xiàn)中查找對應的方法,如果沒找到,則去父類查找,直到找到函數(shù)并實現(xiàn)調用,而不是依賴于引用的類型。
我們知道了接口回調的本質是多態(tài),多態(tài)的本質是JVM的invokevirtual指令,那么我們就不用拘泥于接口和抽象類或者繼承關系這種概念了,我們直接寫一個用普通類實現(xiàn)的回調然后再分析它:
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í)行結果:
如果是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指令調用的 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在調用private方法的時候使用的是invokespecial指令,但是我們不能直接在外部調用私有方法所以就寫了個反射來調用,執(zhí)行結果:
如果有因為是不是因為反射導致的,我們排除一下反射:
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í)行結果:
使用反射和不使用反射的結果一致可以排除反射的干擾
到此這篇關于Java接口回調的本質詳解的文章就介紹到這了,更多相關Java接口回調內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java中的日期時間類實例詳解(Date、Calendar、DateFormat)
在JDK1.0中,Date類是唯一的一個代表時間的類,但是由于Date類不便于實現(xiàn)國際化,所以從JDK1.1版本開始,推薦使用Calendar類進行時間和日期處理,這篇文章主要介紹了Java中的日期時間類詳解(Date、Calendar、DateFormat),需要的朋友可以參考下2023-11-11解決springboot application.properties server.port配置問題
這篇文章主要介紹了解決springboot application.properties server.port配置問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08Java中BigDecimal的加減乘除、比較大小與使用注意事項
對于不需要任何準確計算精度的數(shù)字可以直接使用float或double,但是如果需要精確計算的結果,則必須使用BigDecimal類,而且使用BigDecimal類也可以進行大數(shù)的操作,下面這篇文章給大家介紹了Java中BigDecimal的加減乘除、比較大小與使用注意事項,需要的朋友可以參考下。2017-11-11Springboot整合Swagger2后訪問swagger-ui.html 404報錯問題解決方案
這篇文章主要介紹了Springboot整合Swagger2后訪問swagger-ui.html 404報錯,本文給大家分享兩種解決方案,結合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-06-06