Java 回調函數

 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();   
    }   
}

你們看到了testTime()方法,就只有"//測試方法"是須要改變的,下面咱們來作一個函數實現相同功能但更靈活:
首先定一個回調接口:
java 代碼
public   interface CallBack {   
    //執行回調操做的方法    
    void execute();   
}

而後再寫一個工具類:
java 代碼
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 事件驅動編程模型

相關文章
相關標籤/搜索