最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java回調(diào)方法詳解

 更新時間:2017年01月04日 10:48:52   作者:byhieg  
本篇文章主要介紹了Java回調(diào)方法的步驟、回調(diào)的例子、異步回調(diào)與同步回調(diào)、回調(diào)方法在通信中的應(yīng)用等。具有一定的參考價值,下面跟著小編一起來看下吧

回調(diào)在維基百科中定義為:

在計(jì)算機(jī)程序設(shè)計(jì)中,回調(diào)函數(shù),是指通過函數(shù)參數(shù)傳遞到其他代碼的,某一塊可執(zhí)行代碼的引用。

其目的是允許底層代碼調(diào)用在高層定義的子程序。

舉個例子可能更明白一些:以Android中用retrofit進(jìn)行網(wǎng)絡(luò)請求為例,這個是異步回調(diào)的一個例子。

在發(fā)起網(wǎng)絡(luò)請求之后,app可以繼續(xù)其他事情,網(wǎng)絡(luò)請求的結(jié)果一般是通過onResponse與onFailure這兩個方法返回得到。看一下相關(guān)部分的代碼:

call.enqueue(new Callback<HistoryBean>() {
      @Override
      public void onResponse(Call<HistoryBean> call, Response<HistoryBean> response) {
        HistoryBean hb = response.body();
        if(hb == null) return;
        showText.append(hb.isError() + "");
        for(HistoryBean.ResultsBean rb : hb.getResults()){
          showText.append(rb.getTitle() + "/n");
        }
      }
      @Override
      public void onFailure(Call<HistoryBean> call, Throwable t) {
      }
    });

忽略上面CallBack中的泛型,按照維基百科中的定義,匿名內(nèi)部類里面的全部代碼可以看成函數(shù)參數(shù)傳遞到其他代碼的,某一塊可執(zhí)行代碼的引用。 onResponse與onFailure這兩個方法就是回調(diào)方法。底層的代碼就是已經(jīng)寫好不變的網(wǎng)絡(luò)請求部分,高層定義的子程序就是回調(diào),因?yàn)榫唧w的實(shí)現(xiàn)交給了使用者,所以具備了很高的靈活性。上面就是通過enqueue(Callback callback)這個方法來關(guān)聯(lián)起來的。

回調(diào)方法的步驟

上面說的回調(diào)是很通用的概念,放到程序書寫上面,就可以說:

A類中調(diào)用B類中的某個方法C,然后B類中在反過來調(diào)用A類中的方法D,在這里面D就是回調(diào)方法。B類就是底層的代碼,A類是高層的代碼。

所以通過上面的解釋,我們可以推斷出一些東西,為了表示D方法的通用性,我們采用接口的形式讓D方法稱為一個接口方法,那么如果B類要調(diào)用A類中的方法D,那勢必A類要實(shí)現(xiàn)這個接口,這樣,根據(jù)實(shí)現(xiàn)的不同,就會有多態(tài)性,使方法具備靈活性。

A類要調(diào)用B類中的某個方法C,那勢必A類中必須包含B的引用,要不然是無法調(diào)用的,這一步稱之為注冊回調(diào)接口。那么如何實(shí)現(xiàn)B類中反過來調(diào)用A類中的方法D呢,直接通過上面的方法C,B類中的方法C是接受一個接口類型的參數(shù),那么只需要在C方法中,用這個接口類型的參數(shù)去調(diào)用D方法,就實(shí)現(xiàn)了在B類中反過來調(diào)用A類中的方法D,這一步稱之為調(diào)用回調(diào)接口。

這也就實(shí)現(xiàn)了B類的C方法中,需要反過來再調(diào)用A類中的D方法,這就是回調(diào)。A調(diào)用B是直調(diào),可以看成高層的代碼用底層的API,我們經(jīng)常這樣寫程序。B調(diào)用A就是回調(diào),底層API需要高層的代碼來執(zhí)行。

最后,總結(jié)一下,回調(diào)方法的步驟:

  • A類實(shí)現(xiàn)接口CallBack callback
  • A類中包含了一個B的引用
  • B中有一個參數(shù)為CallBack的方法f(CallBack callback)
  • 在A類中調(diào)用B的方法f(CallBack callback)——注冊回調(diào)接口
  • B就可以在f(CallBack callback)方法中調(diào)用A的方法——調(diào)用回調(diào)接口

回調(diào)的例子

我們以一個兒子在玩游戲,等媽媽把飯做好在通知兒子來吃為例,按照上面的步驟去寫回調(diào);

上面的例子中,顯然應(yīng)該兒子來實(shí)現(xiàn)回調(diào)接口,母親調(diào)用回調(diào)接口。所以我們先定義一個回調(diào)接口,然后讓兒子去實(shí)現(xiàn)這個回調(diào)接口。

其代碼如下:

public interface CallBack {
  void eat();
}
public class Son implements CallBack{
  private Mom mom;
  //A類持有對B類的引用
  public void setMom(Mom mom){
    this.mom = mom;
  }
  @Override
  public void eat() {
    System.out.println("我來吃飯了");
  }
  public void askMom(){
    //通過B類的引用調(diào)用含有接口參數(shù)的方法。
     System.out.println("飯做了嗎?");
    System.out.println("沒做好,我玩游戲了");
    new Thread(() -> mom.doCook(Son.this)).start();
    System.out.println("玩游戲了中......");
  }
}

然后我們還需要定義一個母親的類,里面有一個含有接口參數(shù)的方法doCook

public class Mom {
  //在含有接口參數(shù)的方法中利用接口參數(shù)調(diào)用回調(diào)方法
  public void doCook(CallBack callBack){
    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          System.out.println("做飯中......");
          Thread.sleep(5000);
          callBack.eat();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }).start();
  }
}

我們通過一個測試類:

public class Test {
  public static void main(String[] args) {
    Mom mom = new Mom();
    Son son = new Son();
    son.setMom(mom);
    son.askMom();
  }
}

這個例子就是典型的回調(diào)的例子。Son類實(shí)現(xiàn)了接口的回調(diào)方法,通過askMom這個方法調(diào)用Mom類中的doCook,實(shí)現(xiàn)注冊回調(diào)接口,相當(dāng)于A類中調(diào)用B類的代碼C。在Mom類中的doCook來回調(diào)Son類中的eat,來告訴Son類中的結(jié)果。

這樣,我們就實(shí)現(xiàn)了一個簡單的,符合定義的回調(diào)。

回調(diào)例子的進(jìn)一步探索

我們主要看一下Son類的代碼:

public class Son implements CallBack{
  public Mom mom;
  public Son(Mom mom){
    this.mom = mom;
  }
  public void askMom(){
    System.out.println("飯做了嗎?");
    System.out.println("沒做好,我玩游戲了");
    new Thread(() -> mom.doCook(Son.this)).start();
    System.out.println("玩游戲了中......");
  }
  @Override
  public void eat() {
    System.out.println("好了,我來吃飯了");
  }
}

這個類里面,除了輸出一些語句之外,真正有用的部分是mom.doCook(Son.this)以及重寫eat方法。所以,我們可以通過匿名內(nèi)部類的形式,簡寫這個回調(diào)。其代碼如下:

public class CallBackTest {
  public static void main(String[] args) {
    Mom mom = new Mom();
    new Thread(()-> mom.doCook(() -> System.out.println("吃飯了......"))).start();
  }
}

取消Son類,直接在主方法中通過匿名內(nèi)部類去實(shí)現(xiàn)eat方法。其實(shí)匿名內(nèi)部類就是回調(diào)的體現(xiàn)。

異步回調(diào)與同步回調(diào)

回調(diào)上面我們講了 就是A調(diào)用B類中的方法C,然后在方法C里面通過A類的對象去調(diào)用A類中的方法D。

我們在說一下異步與同步,先說同步的概念

同步

同步指的是在調(diào)用方法的時候,如果上一個方法調(diào)用沒有執(zhí)行完,是無法進(jìn)行新的方法調(diào)用。也就是說事情必須一件事情一件事情的做,做完上一件,才能做下一件。

異步

異步相對于同步,可以不需要等上個方法調(diào)用結(jié)束,才調(diào)用新的方法。所以,在異步的方法調(diào)用中,是需要一個方法來通知使用者方法調(diào)用結(jié)果的。

實(shí)現(xiàn)異步的方式

在Java中最常實(shí)現(xiàn)的異步方式就是讓你想異步的方法在一個新線程中執(zhí)行。

我們會發(fā)現(xiàn)一點(diǎn),異步方法調(diào)用中需要一個方法來通知使用者調(diào)用結(jié)果,結(jié)合上面所講,我們會發(fā)現(xiàn)回調(diào)方法就適合做這個事情,通過回調(diào)方法來通知使用者調(diào)用的結(jié)果。

那異步回調(diào)就是A調(diào)用B的方法C時是在一個新線程當(dāng)中去做的。

上面的母親通知兒子吃飯的例子,就是一個異步回調(diào)的例子。在一個新線程中,調(diào)用doCook方法,最后通過eat來接受返回值,當(dāng)然使用lamdba優(yōu)化之后的,本質(zhì)是一樣的。

同步回調(diào)就是A調(diào)用B的方法C沒有在一個新線程,在執(zhí)行這個方法C的時候,我們什么都不能做,只能等待他執(zhí)行完成。

同步回調(diào)與異步回調(diào)的例子

我們看一個Android中的一個同步回調(diào)的例子:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
       Log.i("button","被點(diǎn)擊");
    }
});

button通過setOnClickListener注冊回調(diào)函數(shù),和上面寫的一樣,通過匿名內(nèi)部類的形式將接口的引用傳進(jìn)去。由于button調(diào)用setOnClickListener沒有新建一個線程,所以這個是同步的回調(diào)。

而異步回調(diào),就是我們開篇講的那個例子:

call.enqueue(new Callback<HistoryBean>() {
      @Override
      public void onResponse(Call<HistoryBean> call, Response<HistoryBean> response) {
        HistoryBean hb = response.body();
        if(hb == null) return;
        showText.append(hb.isError() + "");
        for(HistoryBean.ResultsBean rb : hb.getResults()){
          showText.append(rb.getTitle() + "/n");
        }
      }
      @Override
      public void onFailure(Call<HistoryBean> call, Throwable t) {
      }
    });

這個enqueue方法是一個異步方法去請求遠(yuǎn)程的網(wǎng)絡(luò)數(shù)據(jù)。其內(nèi)部實(shí)現(xiàn)的時候是通過一個新線程去執(zhí)行的。

通過這兩個例子,我們可以看出同步回調(diào)與異步回調(diào)的使用其實(shí)是根據(jù)不同的需求而設(shè)計(jì)。不能說一種取代另一種,像上面的按鈕點(diǎn)擊事件中,如果是異步回調(diào),用戶點(diǎn)擊按鈕之后其點(diǎn)擊效果不是馬上出現(xiàn),而用戶又不會執(zhí)行其他操作,那么會感覺很奇怪。而像網(wǎng)絡(luò)請求的異步回調(diào),因?yàn)槭芟抻谡埱筚Y源可能不存在,網(wǎng)絡(luò)連接不穩(wěn)定等等原因?qū)е掠脩舨磺宄椒▓?zhí)行的時候,所以會用異步回調(diào),發(fā)起方法調(diào)用之后去做其他事情,然后等回調(diào)的通知。

回調(diào)方法在通信中的應(yīng)用

上面提到的回調(diào)方法,除了網(wǎng)絡(luò)請求框架的回調(diào)除外,其回調(diào)方法都是沒有參數(shù),下面,我們看一下在回調(diào)方法中加入?yún)?shù)來實(shí)現(xiàn)一些通信問題。

如果我們想要A類得到B類經(jīng)過一系列計(jì)算,處理后數(shù)據(jù),而且兩個類是不能通過簡單的將B的引用給A類就可以得到數(shù)據(jù)的。我們可以考慮回調(diào)。

步驟如下:

  1. 在擁有數(shù)據(jù)的那個類里面寫一個回調(diào)的接口。-->這里就是B類中寫一個回調(diào)接口
  2. 回調(diào)方法接收一個參數(shù),這個參數(shù)就是要得到的數(shù)據(jù)
  3. 同樣是在這個類里寫一個注冊回調(diào)的方法。
  4. 在注冊回調(diào)方法,用接口的引用去調(diào)用回調(diào)接口,把B類的數(shù)據(jù)當(dāng)做參數(shù)傳入回調(diào)的方法中。
  5. 在A類中,用B類的引用去注冊回調(diào)接口,把B類中的數(shù)據(jù)通過回調(diào)傳到A類中。

上面說的步驟,有點(diǎn)抽象。下面我們看一個例子,一個是Client,一個是Server。Client去請求Server經(jīng)過耗時處理后的數(shù)據(jù)。

public class Client{
  public Server server;
  public String request;
  //鏈接Server,得到Server引用。
  public Client connect(Server server){
    this.server = server;
    return this;
  }
  //Client,設(shè)置request
  public Client setRequest(String request){
    this.request = request;
    return this;
  }
  //異步發(fā)送請求的方法,lamdba表達(dá)式。
  public void enqueue(Server.CallBack callBack){
    new Thread(()->server.setCallBack(request,callBack)).start();
  }
}
public class Server {
  public String response = "這是一個html";
  //注冊回調(diào)接口的方法,把數(shù)據(jù)通過參數(shù)傳給回調(diào)接口
  public void setCallBack(String request,CallBack callBack){
    System.out.println("已經(jīng)收到request,正在計(jì)算當(dāng)中......");
    new Thread(() -> {
      try {
        Thread.sleep(5000);
        callBack.onResponse(request + response);
      } catch (InterruptedException e) {
        e.printStackTrace();
        callBack.onFail(e);
      }
    }).start();
  }
  //在擁有數(shù)據(jù)的那個類里面寫一個接口
  public interface CallBack{
    void onResponse(String response);
    void onFail(Throwable throwable);
  }
}

接下來,我們看一下測試的例子:

public class CallBackTest {
  public static void main(String[] args) {
    Client client = new Client();
    client.connect(new Server()).setRequest("這個文件是什么?").enqueue(new Server.CallBack() {
      @Override
      public void onResponse(String response) {
        System.out.println(response);
      }
      @Override
      public void onFail(Throwable throwable) {
        System.out.println(throwable.getMessage());
      }
    });
  }
}

結(jié)果如下:

已經(jīng)收到request,正在計(jì)算當(dāng)中......
這個文件是什么?這是一個html

以上就是通過回調(diào)的方式進(jìn)行通信。

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!

相關(guān)文章

  • SpringBoot整合Prometheus如何實(shí)現(xiàn)資源監(jiān)控

    SpringBoot整合Prometheus如何實(shí)現(xiàn)資源監(jiān)控

    本文介紹了如何使用Prometheus監(jiān)控SpringBoot應(yīng)用,Prometheus是一個開源的監(jiān)控和告警工具,SpringBootActuator提供了監(jiān)控和管理SpringBoot應(yīng)用的工具,通過添加依賴、配置Actuator和Prometheus,可以實(shí)現(xiàn)對SpringBoot應(yīng)用的實(shí)時監(jiān)控
    2024-12-12
  • 使用JAVA實(shí)現(xiàn)高并發(fā)無鎖數(shù)據(jù)庫操作步驟分享

    使用JAVA實(shí)現(xiàn)高并發(fā)無鎖數(shù)據(jù)庫操作步驟分享

    一個在線2k的游戲,每秒鐘并發(fā)都嚇?biāo)廊?。傳統(tǒng)的hibernate直接插庫基本上是不可行的。我就一步步推導(dǎo)出一個無鎖的數(shù)據(jù)庫操作,詳情看下文
    2013-11-11
  • 寶塔升級JDK版本超詳細(xì)圖文教程

    寶塔升級JDK版本超詳細(xì)圖文教程

    寶塔自動安裝的JDK是一種用于開發(fā)和運(yùn)行Java程序的軟件開發(fā)工具包,下面這篇文章主要給大家介紹了關(guān)于寶塔升級JDK版本的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • 詳解Java中的final關(guān)鍵字

    詳解Java中的final關(guān)鍵字

    子類可以在父類的基礎(chǔ)上改寫父類內(nèi)容,為了避免這種隨意改寫的情況,Java提供了final 關(guān)鍵字,用于修飾不可改變內(nèi)容。本文就來詳細(xì)說說final關(guān)鍵字的使用,需要的可以參考一下
    2022-10-10
  • springboot?publish?event?事件機(jī)制demo分享

    springboot?publish?event?事件機(jī)制demo分享

    這篇文章主要介紹了springboot?publish?event?事件機(jī)制demo,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • SpringMVC中的DispatcherServlet詳細(xì)解析

    SpringMVC中的DispatcherServlet詳細(xì)解析

    這篇文章主要介紹了SpringMVC中的DispatcherServlet詳細(xì)解析,DispatcherServlet也是一個Servlet,它也能通過Servlet的API來響應(yīng)請求,從而成為一個前端控制器,Web容器會調(diào)用Servlet的doGet()以及doPost()等方法,需要的朋友可以參考下
    2023-12-12
  • java使用renderer將pdf按頁轉(zhuǎn)換為圖片

    java使用renderer將pdf按頁轉(zhuǎn)換為圖片

    這篇文章主要為大家詳細(xì)介紹了java使用renderer將pdf按頁轉(zhuǎn)換為圖片,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • java  實(shí)現(xiàn)輸出隨機(jī)圖片實(shí)例代碼

    java 實(shí)現(xiàn)輸出隨機(jī)圖片實(shí)例代碼

    這篇文章主要介紹了java 實(shí)現(xiàn)輸出隨機(jī)圖片實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • java編寫Http服務(wù)器下載工具

    java編寫Http服務(wù)器下載工具

    這篇文章主要介紹了java編寫Http服務(wù)器下載工具的方法,工具很簡單,功能也很簡單,代碼就更簡潔了,卻非常實(shí)用,有需要的小伙伴參考下吧。
    2015-03-03
  • Jmeter對響應(yīng)數(shù)據(jù)實(shí)現(xiàn)斷言代碼實(shí)例

    Jmeter對響應(yīng)數(shù)據(jù)實(shí)現(xiàn)斷言代碼實(shí)例

    這篇文章主要介紹了Jmeter對響應(yīng)數(shù)據(jù)實(shí)現(xiàn)斷言代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09

最新評論

内江市| 平远县| 福清市| 乐亭县| 唐海县| 景谷| 屏东市| 孟村| 仁布县| 东源县| 利川市| 绥棱县| 出国| 定日县| 盐亭县| 将乐县| 无极县| 壤塘县| 绥棱县| 德钦县| 旌德县| 深水埗区| 凤山市| 阳江市| 满城县| 浦北县| 怀安县| 广西| 湖北省| 米泉市| 寿宁县| 屏山县| 泊头市| 金溪县| 裕民县| 罗源县| 通城县| 盈江县| 河间市| 珲春市| 松潘县|