java回呼函數機制

來源:互聯網
上載者:User

標籤:java   回呼函數   使用情境   

Java回呼函數機制


參考了網上的一些資料,下面也做出一些總結,供初學者瞭解學習。


一、 概述

軟體模組之間總是存在著一定的介面,從調用方式上,可以把他們分為三類:同步調用、回調、非同步呼叫 。

同步調用:一種阻塞式調用,調用方要等待對方執行完畢才返回,它是一種單向調用; 

回調:一種雙向調用模式,也就是說,被呼叫者在介面被調用時也會調用對方的介面; 

非同步呼叫:一種類似訊息或事件的機制,解決了同步阻塞的問題,它的調用方向剛好相反,介面的服務在收到某種訊息或發生某種事件時,會主動通知客戶方(即調用客戶方的介面)。




回調和非同步呼叫的關係非常緊密:使用回調來實現非同步訊息的註冊,通過非同步呼叫來實現訊息的通知。


理解非同步和同步

1.通俗說,非同步就是不需要等當前執行的動作完成,就可以繼續執行後面的動作。

2.通常一個程式執行的順序是:從上到下,依次執行。後面的動作必須等前面動作執行完成以後方可執行。這就是和非同步相對的一個概念——同步。


案例:

A、張三打電話給李四,讓李四幫忙寫份材料。

B、李四接到電話的時候,手上有自己的工作要處理,但他答應張三,忙完手上的工作後馬上幫張三寫好材料,並傳真給張三。

C、通完電話後,張三外出辦事。


說明:

張三給李四通完電話後,就出去辦事了,他並不需要等李四把材料寫好才外出。那麼張三讓李四寫材料的訊息就屬於非同步訊息。

相反,如果張三必須等李四把材料寫好才能外出辦事的話,那麼這個訊息就屬於同步訊息了。


二、 非同步實現

傳統的程式執行代碼都是從上到下,一條一條執行。但生活中有很多情況並不是這樣,以上的案例中,如果李四需要幾個小時以後才能幫張三寫好材料的話,那張三就必須等幾個小時,這樣張三可能會崩潰或者抓狂。這種一條龍似的處理,顯示不太合理。


可以使用以下辦法來處理這種問題:

張三找王五去給李四打電話,等李四寫好材料後,由王五轉交給張三。這樣張三就可以外出辦其他的事情了。

 

問題得到了合理的解決,之前張三一條線的工作,由張三和王五兩條線來完成了,兩邊同時進行,彼此不耽誤。

 

三、 電腦語言的實現

辦法有了,如何用程式來類比實現呢?

 

A、以前由一個線程來處理的工作,可以通過新增一個線程來達到非同步目的。

B、最後李四寫好的材料必須交給張三,以做他用。這就是回調。

 

回調你可以這樣來理解:

A發送訊息給B,

B處理好A要求的事情後,將結果返回給A,

A再對B返回的結果來做進一步的處理。

 

四、 類比非同步訊息的發送與回調

A、 回調的實現

/**  * 回調介面  */  public interface CallBack {      /**      * 執行回調方法      * @param objects   將處理後的結果作為參數返回給回調方法      */      public void execute(Object... objects );  }  

Java是物件導向的語言,因此回呼函數就變成了回調介面。


B、 訊息的寄件者

/**  * 簡單本地發送非同步訊息的類  */  public class Local implements CallBack,Runnable{            /**      * 遠程接收訊息的類,類比point-to-point      */      private Remote remote;            /**      * 發送出去的訊息      */      private String message;            public Local(Remote remote, String message) {          super();          this.remote = remote;          this.message = message;      }        /**      * 發送訊息      */      public void sendMessage()      {          /**當前線程的名稱**/          System.out.println(Thread.currentThread().getName());          /**建立一個新的線程發送訊息**/          Thread thread = new Thread(this);          thread.start();          /**當前線程繼續執行**/          System.out.println("Message has been sent by Local~!");      }        /**      * 發送訊息後的回呼函數      */      public void execute(Object... objects ) {          /**列印返回的訊息**/          System.out.println(objects[0]);          /**列印發送訊息的線程名稱**/          System.out.println(Thread.currentThread().getName());          /**中斷髮送訊息的線程**/          Thread.interrupted();      }            public static void main(String[] args)      {          Local local = new Local(new Remote(),"Hello");                    local.sendMessage();      }        public void run() {          remote.executeMessage(message, this);                }  }  

C、 遠程訊息的接收者

/**  * 處理訊息的遠程類  *  */  public class Remote {        /**      * 處理訊息      * @param msg   接收的訊息      * @param callBack  回呼函數處理類      */      public void executeMessage(String msg,CallBack callBack)      {          /**類比遠程類正在處理其他事情,可能需要花費許多時間**/          for(int i=0;i<1000000000;i++)          {                        }          /**處理完其他事情,現在來處理訊息**/          System.out.println(msg);          System.out.println("I hava executed the message by Local");          /**執行回調**/          callBack.execute(new String[]{"Nice to meet you~!"});      }        }  

執行 Local 類的 main 方法。
 
注意Local類中:

remote.executeMessage(message, this);

executeMessage 方法需要接收一個message參數,表示發送出去的訊息,而CallBack參數是他自己,也就是這裡的this。表示發送訊息後,由Local類自己來處理,調用自身的execute方法來處理訊息結果。

如果這裡不是用this,而是用其他的CallBack介面的實作類別的話,那就不能稱之為“回調”了,在OO的世界裡,那就屬於“委派”。也就是說,“回調” 必須是訊息的寄件者來處理訊息結果,否則不能稱之為回調。這個概念必須明確。



五、更多非同步 + 回調 編程模式的例子


1.某天,我打電話向你請教問題,當然是個難題,你一時想不出解決方案,我又不能拿著電話在那裡傻等,於是我們約定:等你想
出辦法後打手機通知我,這樣,我就掛掉電話辦其它事情去了。過了XX分鐘,My Phone響了,你興高采烈的說問題已經搞定,應該如此這般處理。故事到此結束。其中,你後來打手機告訴我結果便是一個“回調”過程;My Phone號碼必須在以前告訴你,這便是註冊回呼函數;我的手機號碼應該有效並且手機能夠接收到你的呼叫,這是回呼函數必須符合介面規範。


2.有一位老闆很忙,他沒有時間盯著員工幹活,然後他告訴自己的僱員,幹完當前這些事情後,告訴他幹活的結果。

建立一個回調介面,讓老闆得告知幹完活如何找到他的方式:留下老闆辦公室地址:

package net.easyway.test;    /**  * 此介面為聯絡的方式,不論是電話號碼還是聯絡地址,作為  * 老闆都必須要實現此介面 *  */  public interface CallBackInterface {        public void execute();  }

建立回調對象,就是老闆本人,因為員工幹完活後要給他打電話,因此老闆必須實現回調介面,不然員工去哪裡找老闆?



package net.easyway.test;    /**  * 老闆是作為上層應用身份出現的,下層應用(員工)是不知道  * 有哪些方法,因此他想被下層應用(員工)調用必須實現此介面  *  */  public class Boss implements CallBackInterface {            @Override      public void execute() {          System.out.println("收到了!!" + System.currentTimeMillis());                }  }

建立控制類,也就是員工對象,他必須持有老闆的地址(回調介面),即使老闆換了一茬又一茬,辦公室不變,總能找到對應的老闆。



package net.easyway.test;    /**  * 員工類,必須要記住,這是一個底層類,底層是不瞭解上層服務的  *  */  public class Employee {        private CallBackInterface callBack = null;            //告訴老闆的連絡方式,也就是註冊      public void setCallBack(CallBackInterface callBack){          this.callBack = callBack;      }            //工人幹活      public void doSome(){          //1.開始幹活了          for(int i=0;i<10;i++){              System.out.println("第【" + i + "】事情幹完了!");          }                    //2.告訴老闆幹完了          callBack.execute();      }  }


測試類別:

package net.easyway.test;    public class Client {        public static void main(String[] args) {                              Employee emp = new Employee();                    //將回調對象(上層對象)傳入,註冊          emp.setCallBack(new Boss());                    //開啟控制器對象運行          emp.doSome();      }    }


著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

java回呼函數機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.