Java回呼函數的理解與實現

來源:互聯網
上載者:User

標籤:已耗用時間   cut   oid   定義   too   tac   callback   ide   rgs   

回呼函數,或簡稱回調,是指通過函數參數傳遞到其它代碼的,某一塊可執行代碼的引用。這一設計允許了底層代碼調用在高層定義的子程式。

在Java裡面,我們使用介面來實現回調。舉個例子

所謂的回調,就是程式員A寫了一段程式(程式a),其中預留有回呼函數介面,並封裝好了該程式。程式員B要讓a調用自己的程式b中的一個方法,於是,他通過a中的介面回調自己b中的方法。

舉個例子:

 1.  首先定義一個類Caller,按照上面的定義就是程式員A寫的程式a,這個類裡面儲存一個介面引用。

public class Caller {    private MyCallInterface callInterface;        public Caller() {    }        public void setCallFunc(MyCallInterface callInterface) {        this.callInterface = callInterface;    }        public void call() {        callInterface.printName();    }}

 2.  介面的定義,方便程式員B根據定義編寫程式實現介面。

public interface MyCallInterface {    public void  printName();}

3.  第三是定義程式員B寫的程式b

public class Client implements MyCallInterface {     @Override    public void printName() {        System.out.println("This is the client printName method");    }}

4.  測試

public class Test {    public static void main(String[] args) {        Caller caller = new Caller();        caller.setCallFunc(new Client());        caller.call();    }}

這樣我們可以看到程式a中保留有介面成員變數,使得程式a可以通過這個介面變數調用這個介面任意實作類別的方法。而程式b被調用的方法就是回呼函數。

 

接下來在看一個具體的實現:

下面使用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();              }          });      }  }

一個待測試的,較耗時的方法:

public   class  TestObject {      /**       * 一個用來被測試的方法,進行了一個比較耗時的迴圈       */       public   static   void  testMethod(){          for ( int  i= 0 ; i< 100000000 ; i++){                        }      }}

這裡我們沒有寫程式b去實現Callback介面,而是通過匿名內部類的方法來實現。同樣也實現了回呼函數。

 

之後我們看看為什麼要使用回呼函數:

所謂回呼函數就是A調用了B,B在適當的時候又反回去調用A。多數時候因為是單線程,A沒有必要等B來調用它,因為A在調用完B之後完全可以調用自己需要的操作。所以回調多見於事件驅動機制裡。因為A在調用完B之後不知道B什麼時候會完成,所以A不知道B什麼時候會完成。而唯一知道B什麼時候完成的當然是B自己了,所以當B完成的時候會通過一個回呼函數通知A,自己已經完成了,這時候A才知道該進行下面的操作。如果不這樣的話,A就只能不斷地詢問B是不是已經完成了(就是輪詢),可見是效率非常低的,實現也很麻煩。

回調通常是在兩個不同的線程間需要同步的情況下才出現的,但是很多時候又沒有必要用訊號量去進行真正的線程同步,因為會很複雜,而且沒有必要。所以有了回調。至於回調要乾的事情,當然是你自己決定了。

 

說一下同步回調和非同步回調:

同步指的是調用一個方法,調用方要等待該方法所執行的任務完全執行完畢,然後控制權回到調用方;非同步指的是調用一個方法,調用方不等該方法執行的任務完畢就返回,當任務執行完畢時會自動執行調用方傳入的一塊代碼。

同步:
void runTask {  doTask1()  doTask2()}

同步調用,執行完 doTask1 在執行 doTask2

非同步
doTask1(new Callback() {  void call() {    doTask3()  }});doTask2();

非同步回調,會同時執行 doTask1 和 doTask2, 在執行完 doTask1 後執行 doTask3

同步調用適合執行耗時短的任務,非同步回調適合執行耗時間長度的任務,而且調用它之後調用的任務沒什麼關係。

看一個非同步回調的案例:

 回調介面類:

/** * 回調模式-回調介面類 */public interface CSCallBack {    public void process(String status);}

 類比用戶端:

/** * 回調模式-類比用戶端類 */public class Client implements CSCallBack {    private Server server;    public Client(Server server) {        this.server = server;    }    public void sendMsg(final String msg){        System.out.println("用戶端:發送的訊息為:" + msg);        new Thread(new Runnable() {            @Override            public void run() {                server.getClientMsg(Client.this,msg);            }        }).start();        System.out.println("用戶端:非同步發送成功");    }    @Override    public void process(String status) {        System.out.println("用戶端:服務端回調狀態為:" + status);    }}

類比服務端:

/** * 回調模式-類比服務端類 */public class Server {    public void getClientMsg(CSCallBack csCallBack , String msg) {        System.out.println("服務端:服務端接收到用戶端發送的訊息為:" + msg);        // 類比服務端需要對資料處理        try {            Thread.sleep(5 * 1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("服務端:資料處理成功,返回成功狀態 200");        String status = "200";        csCallBack.process(status);    }}

 測試類別:

/** * 回調模式-測試類別 */public class CallBackTest {    public static void main(String[] args) {        Server server = new Server();        Client client = new Client(server);        client.sendMsg("Server,Hello~");    }}

 

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.