java 自定义函数的调用_Java/Android中的函数调用回调函数自定义回调函数
在做Android自定義控件時(shí)遇到要自定義回調(diào)函數(shù)的問題,想想自己還暫時(shí)沒有那么精深的技術(shù),趕緊返過頭回來再重新研究Java中回調(diào)函數(shù)的問題。然而不幸的是,網(wǎng)上太多雜亂的帖子和博客都是轉(zhuǎn)來轉(zhuǎn)去,而且都是那一篇“C中的回調(diào)函數(shù).....指針.....java....”,一點(diǎn)看不出來是自己的思路,估計(jì)都是哪哪哪抄來的!(呵呵,要么就是吐槽對了,要么就是我水平太爛讀不懂還妄加評(píng)論
)還有一些很不錯(cuò)的文章,我會(huì)在最后參考中加上鏈接,大家可以看看。
那么來開始我們的正題——什么是回調(diào)函數(shù)?
我們一步步深入,先從函數(shù)調(diào)用開始:
什么是函數(shù)(方法)調(diào)用?
(別的什么語言的都忘了……呵呵,只看Java)Java中的函數(shù)調(diào)用無非就是(1)一個(gè)類中方法為了完成一個(gè)業(yè)務(wù)在執(zhí)行過程中調(diào)用另一個(gè)方法,另一個(gè)方法也可以是自己,那就是遞歸啦;(2)不同類之間的函數(shù)調(diào)用,比如Class B(調(diào)用者Caller)中要調(diào)用Class A對象的一個(gè)方法(被調(diào)用者Callee)(不管A是作為B的成員,還是作為函數(shù)參數(shù)傳進(jìn)來)。方法調(diào)用是我們編程中必不可少的,可能我們平時(shí)視而不見罷了,否則一個(gè)工程的不同CLASS怎么協(xié)同工作呢?雖然簡單,還是畫個(gè)圖說一下吧,待會(huì)對比一下可以更好的解釋回調(diào)的機(jī)制:
如上圖Class B的函數(shù)method_B在執(zhí)行過程中要調(diào)用成員a(Class A)的method_A1方法。
我們剛開始學(xué)的時(shí)候都是這樣做的。但是這樣做存在問題,讓我們來回顧一下我們當(dāng)年學(xué)習(xí)的經(jīng)過,不斷將這個(gè)問題解釋清楚:舉個(gè)例子吧,不然嘴笨表達(dá)不清楚——A類是鳥類,B就是我們的工具類,現(xiàn)在我們要在工具類中完成這樣的需求:通過工具類中的方法method_B完成不同鳥類飛的正確動(dòng)作。
第一階段:顯然就兩個(gè)類完成不了這個(gè)需求!接著我們學(xué)習(xí)了繼承,我們創(chuàng)建了“麻雀”、“大雁”、“鴕鳥”……各種“鳥”類子類,通過不同子類來完成不同的飛法,然后在工具類中創(chuàng)建不同子類的對象賦值給a,這樣需求完成了。但是回頭看看,我們創(chuàng)建了一大堆的子類,而且還用了隱式類型轉(zhuǎn)換(子類賦值給父類),顯然不夠滿意;
第二階段:后來,我們又學(xué)習(xí)了重載函數(shù),在鳥類中創(chuàng)建一系列同名同名的“飛”函數(shù),傳入?yún)?shù)類型分別為麻雀、大雁……,這樣我們就不用隱式轉(zhuǎn)換了,直接調(diào)用鳥類對象a的飛方法,傳入不同的大雁、麻雀……,a就能正確的飛了。這樣需求也完成了,雖然避免了使用隱式轉(zhuǎn)換,但是那些為數(shù)眾多的子類可一個(gè)也沒有落下。這樣做顯然也不符合我們的期望(我們的期望是什么?就是干最少的活,鳥就能正確的飛)。
以上實(shí)現(xiàn)方式的問題就顯而易見了:一方面我們要維護(hù)那些眾多的子類,增加很大的工作量;另一方面,這樣的編碼缺乏靈活性,有多少種鳥你知道嗎,每種鳥又是怎么飛的你知道嗎,如果幾種鳥極為相似,你是創(chuàng)建不同的類呢還是歸為一類?所以有了下邊這種實(shí)現(xiàn)方式,就是采用“回調(diào)函數(shù)”——
什么是回調(diào)函數(shù)?
直接上圖吧:
如上圖,回調(diào)函數(shù)中必然用到接口。下邊是感覺寫得好的一段理解:
在android的學(xué)習(xí)過程中經(jīng)常會(huì)聽到或者見到“回調(diào)”這個(gè)詞,那么什么是回調(diào)呢?所謂的回調(diào)函數(shù)就是:在A類中定義了一個(gè)方法,這個(gè)方法中用到了一個(gè)接口和該接口中的抽象方法,但是抽象方法沒有具體的實(shí)現(xiàn),需要B類去實(shí)現(xiàn),B類實(shí)現(xiàn)該方法后,它本身不會(huì)去調(diào)用該方法,而是傳遞給A類,供A類去調(diào)用,這種機(jī)制就稱為回調(diào)。
我認(rèn)為,上圖中B類的方法method_B在調(diào)用a對象的method_A1時(shí),method_A1執(zhí)行到interface的抽象方法不知道怎么實(shí)現(xiàn),正好B在調(diào)用他的時(shí)候提供了具體實(shí)現(xiàn),所以method_A1返回來調(diào)用method_B提供的實(shí)現(xiàn),這就是回調(diào)。其實(shí),回調(diào)函數(shù)就是在一個(gè)不確定實(shí)現(xiàn)的方法METHOD中用interface或者它的抽象方法留個(gè)口子,留給具體調(diào)用者(調(diào)用前邊那個(gè)不確定的方法METHOD)在調(diào)用時(shí)提供具體實(shí)現(xiàn)來補(bǔ)上那個(gè)口子。從而達(dá)到更靈活地編碼的目的,也大大減少了子類的使用。就拿上邊沒完的例子繼續(xù)吧——
我們這樣來實(shí)現(xiàn):先定義一個(gè)接口,接口中聲明抽象方法“飛”;在“鳥”類的“起飛”方法中把接口對象作為一個(gè)參數(shù)傳進(jìn)來,剩下的該怎么做就怎么做,遇到要飛的地方不知道具體怎么飛就調(diào)用接口提供的抽象方法“飛”;在工具類中調(diào)用“鳥”類的“起飛”方法時(shí)要實(shí)現(xiàn)了抽象方法的對象作為參數(shù)傳入,然后你想讓它怎么飛就怎么飛,具體實(shí)現(xiàn)是你調(diào)用的時(shí)候現(xiàn)寫的。怎么樣,這樣的實(shí)現(xiàn)好吧?不用隱式轉(zhuǎn)換,不用大量子類,調(diào)用的時(shí)候遇到什么鳥就怎么飛,達(dá)到了我們少干活的目的!
什么是自定義回調(diào)函數(shù)?
自定義回調(diào)函數(shù),顧名思義,就是我們自己定義的回調(diào)函數(shù)。其實(shí)上邊那個(gè)例子就是自定義回調(diào)函數(shù)!我們習(xí)慣上把別人定義好的回調(diào)函數(shù)叫作回調(diào)函數(shù),Android系統(tǒng)中TextView、ImageView等和它們的子類控件的Onclick事件響應(yīng)就是典型的回調(diào)機(jī)制。關(guān)于這個(gè)這位大蝦講得比我好——詳細(xì)介紹Android中回調(diào)函數(shù)機(jī)制,詳細(xì)看看會(huì)很有幫助的!
一個(gè)簡單的自定義回調(diào)函數(shù)的例子
最后在舉個(gè)簡單的有代碼的例子,看一下回調(diào)函數(shù)的運(yùn)行過程:
首先,我們定義一個(gè)interface:
public?interface?MyInterface?{
void?sayYourName();
}
接著,我們定義一個(gè)類,其中一個(gè)方法以接口MyInterface類型的對象作為參數(shù):
public?class?MyClass?{
public?MyClass()?{
Log.e("WangJ",?"MyClass-constructor");?????????//標(biāo)注構(gòu)造函數(shù)
}
/*?用接口類型的對象作為輸入?yún)?shù)?*/
public?void?sayYourName(MyInterface?myInterface){
Log.e("WangJ",?"MyClass-sayYourName_start");????//標(biāo)注方法開始
myInterface.sayYourName();??????????????????????//遇到不知道具體實(shí)現(xiàn)的時(shí)候就用接口的抽象方法
Log.e("WangJ",?"MyClass-sayYourName_finish");???//方法結(jié)束
}
}
最后,我們在Activity中調(diào)用這個(gè)類,創(chuàng)建對象并調(diào)用其方法,期間實(shí)現(xiàn)接口中抽象方法的具體實(shí)現(xiàn)邏輯,供回調(diào)使用:
public?class?MainActivity?extends?Activity?{
@Override
protected?void?onCreate(Bundle?savedInstanceState)?{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyClass?myClass?=?new?MyClass();
myClass.sayYourName(new?MyInterface()?{?????????????????????//實(shí)現(xiàn)接口并作為參數(shù)傳入
@Override
public?void?sayYourName()?{
Log.e("WangJ",?"callBack-interface-implementor");????//具體操作實(shí)現(xiàn)
}
});
}
}
好了,運(yùn)行一下(我們這個(gè)例子沒有任何界面,即默認(rèn)Activity的界面,看日志):
運(yùn)行的順序就是我們之前理解的:在B中調(diào)用A中的方法,A中方法在運(yùn)行到接口中抽象方法時(shí)返回B中尋找具體實(shí)現(xiàn)(這就是回調(diào)),回調(diào)完成后繼續(xù)執(zhí)行下邊未完成的步驟。
好了,以上就是我所認(rèn)識(shí)的回調(diào)函數(shù),聽起來高深,在你弄懂以后發(fā)現(xiàn)也沒有太大的難度。但是想想Java研發(fā)者在設(shè)計(jì)這種機(jī)制的時(shí)候是多么有遠(yuǎn)見啊(好崇拜,雖然不知道他是誰)!文筆有限,理解不夠,如有不足或錯(cuò)誤,歡迎指正!最后如約附上那幾篇不錯(cuò)的文章——
總結(jié)
以上是生活随笔為你收集整理的java 自定义函数的调用_Java/Android中的函数调用回调函数自定义回调函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 安卓 html_java –
- 下一篇: android 原始编译过程,Andro