Java 回调函数
1. 什么是回調函數
回調函數(callback Function),顧名思義,用于回調的函數。 回調函數只是一個功能片段,由用戶按照回調函數調用約定來實現的一個函數?;卣{函數是一個工作流的一部分,由工作流來決定函數的調用(回調)時機?;卣{函數包含下面幾個特性:
1、屬于工作流的一個部分;
2、必須按照工作流指定的調用約定來申明(定義);
3、他的調用時機由工作流決定,回調函數的實現者不能直接調用回調函數來實現工作流的功能;
2. 回調機制
回調機制是一種常見的設計模型,他把工作流內的某個功能,按照約定的接口暴露給外部使用者,為外部使用者提供數據,或要求外部使用者提供數據。
=======================================================
java回調機制:
軟件模塊之間總是存在著一定的接口,從調用方式上,可以把他們分為三類:同步調用、回調和異步調用。
?
同步調用:一種阻塞式調用,調用方要等待對方執行完畢才返回,它是一種單向調用;
回 調:一種雙向調用模式,也就是說,被調用方在接口被調用時也會調用對方的接口;
異步調用:一種類似消息或事件的機制,不過它的調用方向剛好相反,接口的服務在收到某種訊息或發生某種事件時,會主動通知客戶方(即調用客戶方的接口)。
回調和異步調用的關系非常緊密:使用回調來實現異步消息的注冊,通過異步調用來實現消息的通知。
========================================================
?
用Java里的例子:
?
package callbackexample; public interface ICallBack { //需要回調的方法 public void postExec(); }?
另外的一個類:
package callbackexample; public class FooBar { //組合聚合原則 private ICallBack callBack; public void setCallBack(ICallBack callBack) { this.callBack = callBack; doSth(); } public void doSth() { callBack.postExec(); } }?
?
第二個類在測試類里面,是一個匿名類:
package callbackexample; 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()這個方法?,F在有另一個類FooBar它有個方法 setCallBack(ICallBack callBack) ,并且setCallBack方法調用了callBack的postExec()方法。
如果現在,我們使用一個Myclass 的實例myClass,將它作為參數帶入到setCallBack(ICallBack callBack)方法中,我們就說setCallBack(ICallBack callBack)方法回調了myClass的postExec()方法。
?
以下轉自:http://kidult.javaeye.com/blog/148982
下面使用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 事件驅動編程模型.
?
?
?
回調方法另一測試用例:
熟悉MS-Windows和X Windows事件驅動設計模式的開發人員,通常是把一個方法的指針傳遞給事件源,當某一事件發生時來調用這個方法(也稱為“回調”)。Java的面向對象的模型目前不支持方法指針,似乎不能使用這種方便的機制。
Java支持interface,通過interface可以實現相同的回調。其訣竅就在于定義一個簡單的interface,申明一個被希望回調的方法。
例如,假定當某一事件發生時會得到通知,我們可以定義一個interface:
public interface InterestingEvent {
??? // 這只是一個普通的方法,可以接收參數、也可以返回值
??? public void interestingEvent();
}
這樣我們就有了任何一個實現了這個接口類對象的手柄grip。
當一事件發生時,需要通知實現InterestingEvent 接口的對象,并調用interestingEvent() 方法。
class EventNotifier {
??? private InterestingEvent ie;
??? private boolean somethingHappened;
??? public EventNotifier(InterestingEvent event) {
??? ??? ie = event;
??? ??? somethingHappened = false;
??? }
??? public void doWork() {
??? ??? if (somethingHappened) {
??? ??? ??? // 事件發生時,通過調用接口的這個方法來通知
??? ??? ??? ie.interestingEvent();
??? ??? }??? ???
??? }
}
在這個例子中,用somethingHappened 來標志事件是否發生。
希望接收事件通知的類必須要實現InterestingEvent 接口,而且要把自己的引用傳遞給事件的通知者。
public class CallMe implements InterestingEvent {
??? private EventNotifier en;
??? public CallMe() {
??? ??? // 新建一個事件通知者對象,并把自己傳遞給它
??? ??? en = new EventNotifier(this);
??? }
??? // 實現事件發生時,實際處理事件的方法
??? public void interestingEvent() {
??? ??? // 這個事件發生了,進行處理
??? }
}
以上是通過一個非常簡單的例子來說明Java中的回調的實現。
當然,也可以在事件管理或事件通知者類中,通過注冊的方式來注冊多個對此事件感興趣的對象。
1. 定義一個接口InterestingEvent ,回調方法nterestingEvent(String event) 簡單接收一個String 參數。
interface InterestingEvent {
??? public void interestingEvent(String event);
}
2. 實現InterestingEvent接口,事件處理類
class CallMe implements InterestingEvent {
??? private String name;
??? public CallMe(String name){
??? ??? this.name = name;
??? }???
??? public void interestingEvent(String event) {
??? ??? System.out.println(name + ":[" +event? + "] happened");
??? }
}
3. 事件管理者,或事件通知者
class EventNotifier {
??? private List<CallMe> callMes = new ArrayList<CallMe>();
???
??? public void regist(CallMe callMe){
??? ??? callMes.add(callMe);
??? }
???
??? public void doWork(){
??? ??? for(CallMe callMe: callMes) {
??? ??? ??? callMe.interestingEvent("sample event");
??? ??? }
??? }???
}
4. 測試
public class CallMeTest {
??? public static void main(String[] args) {
??? ??? EventNotifier ren = new EventNotifier();
??? ??? CallMe a = new CallMe("CallMe A");
??? ??? CallMe b = new CallMe("CallMe B");
??? ??? // regiest
??? ??? ren.regist(a);
??? ??? ren.regist(b);
??? ???
??? ??? // test
??? ??? ren.doWork();??? ???
??? }
}
總結
- 上一篇: checkboxlist与数组结合用的技
- 下一篇: xp系统oracle数据库,Oracle