1. 什麼是回調函數
回調函數(callback Function),顧名思義,用於回調的函數。 回調函數只是一個功能片斷,由用戶按照回調函數調用約定來實現的一個函數。回調函數是一個工做流的一部分,由工做流來決定函數的調用(回調)時機。回調函數包含下面幾個特性:
一、屬於工做流的一個部分;
二、必須按照工做流指定的調用約定來申明(定義);
三、他的調用時機由工做流決定,回調函數的實現者不能直接調用回調函數來實現工做流的功能;
2. 回調機制
回調機制是一種常見的設計模型,他把工做流內的某個功能,按照約定的接口暴露給外部使用者,爲外部使用者提供數據,或要求外部使用者提供數據。java
=======================================================編程
java回調機制:app
軟件模塊之間老是存在着必定的接口,從調用方式上,能夠把他們分爲三類:同步調用、回調和異步調用。異步
同步調用:一種阻塞式調用,調用方要等待對方執行完畢才返回,它是一種單向調用;函數
回 調:一種雙向調用模式,也就是說,被調用方在接口被調用時也會調用對方的接口;工具
異步調用:一種相似消息或事件的機制,不過它的調用方向恰好相反,接口的服務在收到某種訊息或發生某種事件時,會主動通知客戶方(即調用客戶方的接口)。post
回調和異步調用的關係很是緊密:使用回調來實現異步消息的註冊,經過異步調用來實現消息的通知。測試
========================================================this
用Java裏的例子:spa
interface ICallBack { //須要回調的方法 public void postExec(); }
另外的一個類:
class FooBar { //組合聚合原則 private ICallBack callBack; public void setCallBack(ICallBack callBack) { this.callBack = callBack; doSth(); } public void doSth() { callBack.postExec(); } }
第二個類在測試類裏面,是一個匿名類:
public class test{ public static void main(String[] args) { FooBar foo = new FooBar(); foo.setCallBack(new ICallBack() { public void postExec() { System.out.println("在Test類中實現但不能被Test的對象引用,而由FooBar對象調用"); } }); } }
上訴的代碼:
1.兩個類:匿名類和FooBar
2.匿名類實現接口ICallBack(在test測試的main方法中用匿名類的形式實現)
3.FooBar 擁有一個參數爲ICallBack接口類型的函數setCallBack(ICallBack o)
4.匿名類運行時調用FooBar中setCallBack函數,以自身傳入參數
5.FooBar已取得匿名類,就能夠隨時回調匿名類中所實現的ICallBack接口中的方法
==================================
1。首先回調方法的概念與「構造方法」的概念是不同的,它不是指java中某個具備特殊意義或用途的方法。
2。稱它爲方法的「回調」更恰當一些,它是指方法的一種調用方式。任何一個被「回調」的方法,皆可稱之爲「回調方法」
3。方法的回調一般發生在「java接口」和「抽象類」的使用過程當中。
假設有接口名爲 ICallBack 其中有方法名爲postExec()
有類Myclass 實現了該接口,也就是必定實現了postExec()這個方法。如今有另外一個類FooBar它有個方法 setCallBack(ICallBack callBack) ,而且setCallBack方法調用了callBack的postExec()方法。
若是如今,咱們使用一個Myclass 的實例myClass,將它做爲參數帶入到setCallBack(ICallBack callBack)方法中,咱們就說setCallBack(ICallBack callBack)方法回調了myClass的postExec()方法。
下面使用java回調函數來實現一個測試函數運行時間的工具類:
若是咱們要測試一個類的方法的執行時間,一般咱們會這樣作:
java 代碼
public class TestObject { /** * 一個用來被測試的方法,進行了一個比較耗時的循環 */ public static void testMethod(){ for ( int i= 0 ; i< 100000000 ; i++){ } } /** * 一個簡單的測試方法執行時間的方法 */ public void testTime(){ long begin = System.currentTimeMillis(); //測試起始時間 testMethod(); //測試方法 long end = System.currentTimeMillis(); //測試結束時間 System.out.println("[use time]:" + (end - begin)); //打印使用時間 } public static void main(String[] args) { TestObject test=new TestObject(); test.testTime(); } }
public interface CallBack { //執行回調操做的方法 void execute(); }
public class Tools { /** * 測試函數使用時間,經過定義CallBack接口的execute方法 * @param callBack */ public void testTime(CallBack callBack) { long begin = System.currentTimeMillis(); //測試起始時間 callBack.execute(); ///進行回調操做 long end = System.currentTimeMillis(); //測試結束時間 System.out.println("[use time]:" + (end - begin)); //打印使用時間 } public static void main(String[] args) { Tools tool = new Tools(); tool.testTime(new CallBack(){ //定義execute方法 public void execute(){ //這裏能夠加放一個或多個要測試運行時間的方法 TestObject.testMethod(); } }); } }
你們看到,testTime()傳入定義callback接口的execute()方法就能夠實現回調功能
==============================================================
若是說匿名內部類的方式不容易理解,能夠看下面的例子
其技巧就是:定義一個簡單接口,並在該接口中聲明咱們要調用的方法。
下面舉一個例子:
假定咱們但願在某個事件發生時獲得通知。咱們能夠定義一個接口:
/*
* 在某個事件發生時獲得通知.
*/
public interface InterestingEvent {
public void interestingEvent();
}
此接口中的方法,是個沒有返回值的也沒有任何參數,若是您願意也能夠有返回值,也能夠帶參數.這就要看具體需求而定.
這使得咱們能夠控制實現該接口的類的任何對象。所以,咱們沒必要關心任何外部類型信息。與在將 C++ 代碼用於Motif 時使用窗口小部件的數據域來容納對象指針的難以控制的 C 函數相比,這種方法要好得多。
實現接口的代碼以下:
public class CallMe implements InterestingEvent { public CallMe() { } public void interestingEvent() { System.out.println("發生了打印事件,哈哈"); } } public class CallYou implements InterestingEvent { public CallYou() { } public void interestingEvent() { System.out.println("發生了查詢事件,哈哈"); } } 發出事件信號的類必須等待實現了 InterestingEvent 接口的對象,並在適當時候調用 interestingEvent() 方法。 public class EventNotifier { private InterestingEvent ie; private boolean somethingHappened ; public EventNotifier() { somethingHappened = true ; } public void setInterestingEvent(InterestingEvent ie){ this.ie = ie ; } public void doWork(){ if(somethingHappened){ ie.interestingEvent(); } } } 下面作一下測試. public class Test { /** * @param args */ public static void main(String[] args) { CallMe cm = new CallMe(); CallYou cy = new CallYou(); EventNotifier en = new EventNotifier(); en.setInterestingEvent(cm); en.doWork(); en.setInterestingEvent(cy); en.doWork(); } }
此測試在發生指定的調用CalMe事件時,就掃行CallMe下的命令,如發生CallYou事件時,就調用CallYou下的命令.此種方法能夠結合Command模式.實現MS-Windows 和 X Window System 事件驅動編程模型