函式回撥機制、非同步函式回撥機制圖例詳解
函式回撥機制,一種雙向呼叫思想,簡單來說就是,如下圖所示:
在層次一中的方法一(函式)呼叫層次二中的方法,並傳入函式二的地址,而這個被呼叫的方法又會呼叫層次一中的方法,這個最後被呼叫的方法二就是回撥方法。方法三呼叫方法二就是回撥的過程。一個有意思的例子,大家可以先感受一下:“諸葛亮給趙子龍一個錦囊,吩咐他危急時開啟按錦囊指示辦, 錦囊裡的命令就是回撥函式,危急時刻就是回撥的時機。”
在Java中,這個“層次”可以理解為類,是兩個類互相呼叫對方的方法;也可以理解為應用類(高層)呼叫類庫方法(低層),並傳入一個自定義的方法以完成某些功能。
說到“呼叫”,模組之間總是存在這一定的介面,模組之間通過這些介面呼叫以通訊聯絡,從呼叫方式上看,可以分為三類:同步呼叫、回撥和非同步呼叫
同步呼叫是一種阻塞式呼叫,也是我們在寫程式中經常使用的;
回撥是一種雙向的呼叫模式;
非同步呼叫是一種類似訊息或事件的機制,解決了同步阻塞的問題,舉例來講:A通知B後,他們各走各的路,互不影響,不用像同步呼叫那樣,A通知B後,非得等到B走完後,A才繼續走。回撥是非同步呼叫的基礎。下面以一個網路上很流行的例子為基礎,理解非同步回撥機制。
非同步回撥典型例子:
提問者A有個問題"1+1=?",於是A打電話給回答者B,B說他現在很忙,忙完了才能給他想答案,A心想我不能這麼一直等著把,於是說:“那咱們約定好,B你想出答案了以打電話的形式告訴我”,掛了電話A也去忙他自己的事了,過了一會B想出答案按A約定好的方式打電話告訴了B答案。
下面以程式碼形式描述這個過程:
/**
* 這是一個回撥介面,裡面定義的方法就是回撥函式
*/
public interface CallBack {
/**
* 這是一個回撥函式,用於回答者B知道答案後給提問者A回電話,並告知提問者A答案是什麼
* 這個回電話的方式callBack是提問者A確定的,所以這個方法的實現類是A類
* 這個回電話的內容result是回答者B提供的,所以這個變數的值是在B類中確定的
*/
public void callBack(String result);
}
/** * 提問者A類 */ public class A implements CallBack{ /** * 提問者A是知道回答者B的聯絡方式的 * 這裡以一個B類引用代表,並在構造方法中傳入B例項物件 */ private B b; public A(B b){ this.b = b; } /** * 提問者A向回答者B打電話提問題 * 這裡以一個call方法表示,並把問題引數傳入 */ public void call(final String question){ /** * 建立提問者A執行緒,與回答者B執行緒結合,構成一個非同步的環境 */ new Thread(new Runnable() { @Override public void run() { /** * B接電話,聽問題 * 這裡以呼叫回答者B的answer方法表示,傳入回撥方法類引數、問題引數,以表示誰打的電話,問啥了 * 因為A類實現了CallBack介面,所以A類就是回撥方法類,回撥方法類實現了回撥方法 */ b.answer(A.this, question); } }).start(); /** * 提問者提完問,去幹別事情 */ doOtherThing(); } public void doOtherThing(){ System.out.println("我是提問者A,我問完問題就去幹別的事情了!"); } /** * 剛剛說到,這個回電話的方式callBack是提問者A確定的,所以這個方法的實現類是A類 * 所以這裡實現回撥方法,代表回覆的方法是回電話,由回答者B呼叫 */ @Override public void callBack(String result) { System.out.println("B呼叫A定義的回撥函式:回答者B告訴提問者A,問題的答案是:"+ result); } }
/**
* 回答者B類
*/
public class B {
/**
* 回答者B接電話,聽問題 這裡以呼叫回答者B的answer方法表示,傳入回撥方法類、問題引數,以表示誰打的電話,問啥了
*/
public void answer(CallBack callBack, String question) {
System.out.println("A呼叫B的接電話方法:我是回答者B,提問者A問的問題是:" + question);
/**
* 模擬回答者B先忙自己的事
*/
System.out.println("我是回答者B,我接完電話先去忙我自己的事!");
for (int i = 0; i < 100000; i++) {
}
String result = "2";
System.out.println("我是回答者B,我知道了答案是:" + result);
/**
* 呼叫回撥函式,打電話告知A答案是什麼
*/
callBack.callBack(result);
}
}
/**
* 場景測試類
*/
public class test {
public static void main(String args[]){
/**
* 例項化回答者B
*/
B b = new B();
/**
* 例項化提問者A
*/
A a = new A(b);
/**
* A向B提問,開始
*/
a.call("1 + 1 = ?");
}
}
(例子原版源自:xiaanming的部落格(http://blog.csdn.net/xiaanming/article/details/17483273))
執行結果:
函式回撥機制也應用於鉤子方法,這個可以參考部落格:點選開啟連結