一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 詳解Java的回調機制

詳解Java的回調機制

2020-06-26 16:10Q-WHai JAVA教程

最近學習java,接觸到了回調機制(CallBack)。初識時感覺比較混亂,而且在網上搜索到的相關的講解,本文介紹了Java的回調機制,有興趣的同學可以了解一下。

模塊之間總是存在這一定的接口,從調用方式上看,可以分為三類:同步調用、回調和異步調用。下面著重詳解回調機制。

1. 概述

Java 中的回調機制是一個比較常見的機制,只是有可能在你的程序中使用得比較少,在一些大型的框架中回調機制隨處可見。本文就通過一些具體的實例,慢慢走近 Java 的回調機制。

2.回調

所謂回調:就是A類中調用B類中的某個方法C,然后B類中反過來調用A類中的方法D,D這個方法就叫回調方法。實際在使用的時候,也會有不同的回調形式,比如下面的這幾種。

2.1 同步回調

這里我假設這樣的一種情況。

A 公司的總監 B 跟他的下屬(項目經理 C)說要做一個調研,不過不用 C 自己親力親為。可以讓經理 C 去安排他下面的程序員 D 去完成。經理 C 找到了程序員 D,并告訴他,現在要完成一個調研任務。并且把調研的結果告訴經理 C。如果有問題,還是要繼續的。 因為這里是 C 讓 D 去做一件事情,之后 D 還是要將結果與 C 進行溝通。這樣就是回調的模型了。下面是一般回調的類圖:

詳解Java的回調機制

首先我們要有一個回調的接口 CallbackInterface

CallbackInterface.java

?
1
2
3
public interface CallbackInterface {
  public boolean check(int result);
}

背景里,程序員 D 是要將結果與項目經理 C 進行溝通的,所以這里項目經理需要實現上面的回調接口:

Manager.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Manager implements CallbackInterface {
 
  private Programmer programmer = null;
 
  public Manager(Programmer _programmer) {
    this.programmer = _programmer;
  }
 
  /**
   * 用于 Boss 下達的委托
   */
  public void entrust() {
    arrange();
  }
 
  // 進行安排下屬進行 study 工作
  private void arrange() {
    System.out.println("Manager 正在為 Programmer 安排工作");
    programmer.study(Manager.this);
    System.out.println("為 Programmer 安排工作已經完成,Manager 做其他的事情去了。");
  }
 
  @Override
  public boolean check(int result) {
    if (result == 5) {
      return true;
    }
    return false;
  }
 
}

對于程序員 D 來說他需要持有一個經理 C 的引用,以便與他溝通。不過,這里是總監 B 讓 經理 C 去安排的任務。也就是說這里也可以讓其他的經理,比如說經理 B1, B2等等。因為經理都實現了回調的接口,所以這里就可以直接讓程序員 D 持有這個接口就可以了。如下:

Programmer.java

?
1
2
3
4
5
6
7
8
9
10
11
12
public class Programmer {
 
  public void study(CallbackInterface callback) {
    int result = 0;
    do {
      result++;
      System.out.println("第 " + result + " 次研究的結果");
    } while (!callback.check(result));
 
    System.out.println("調研任務結束");
  }
}

對于總監來說就更簡單明了了,因為這相當于一個 Client 測試:

Boss.java

?
1
2
3
4
5
6
7
public class Boss {
 
  public static void main(String[] args) {
    Manager manager = new Manager(new Programmer());
    manager.entrust();
  }
}

運行結果:

Manager 正在為 Programmer 安排工作
第 1 次研究的結果
第 2 次研究的結果
第 3 次研究的結果
第 4 次研究的結果
第 5 次研究的結果
調研任務結束
為 Programmer 安排工作已經完成,Manager 做其他的事情去了。

2.2 異步回調

還是上面的例子,你的項目經理不可能要一直等你調研的結果。而是把這個任務交給你之后,他就不管了,他做他的,你做你的。所以,這里需要對回調的函數進行異步處理。
所以,這里我們需要修改 Programmer 類的代碼,修改如下:

Programmer.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Programmer {
 
  public Programmer() {
  }
 
  public void study(CallbackInterface callback) {
    new StudyThread(callback).start();
  }
 
  // --------------------------- Programmer 正在做的工作 ---------------------------
 
  class StudyThread extends Thread {
 
    CallbackInterface callback = null;
 
    public StudyThread(CallbackInterface _callback) {
      callback = _callback;
    }
 
    @Override
    public void run() {
      int result = 0;
      do {
        result++;
        System.out.println("第 " + result + " 次研究的結果");
      } while (!callback.check(result));
 
      System.out.println("調研任務結束");
    }
  }
}

運行結果:

Manager 正在為 Programmer 安排工作
為 Programmer 安排工作已經完成,Manager 做其他的事情去了。
第 1 次研究的結果
第 2 次研究的結果
第 3 次研究的結果
第 4 次研究的結果
第 5 次研究的結果
調研任務結束

2.3 閉包與回調

閉包(closure)是一個可調用的對象,它記錄了一些信息,這些信息來自于創建它的作用域。

2.3.1 普通調用

首先,我們可以看看在正常情況下的調用是怎么進行的。
Incrementable.java

?
1
2
3
interface Incrementable {
  void increment();
}

這是一個普通的接口(在普通調用里只是普通接口,在回調中就是回調接口,這一點應該很好理解吧)。

Callee1.java

?
1
2
3
4
5
6
7
8
9
10
11
class Callee1 implements Incrementable {
 
  private int i = 0;
 
  @Override
  public void increment() {
    i++;
    System.out.println(i);
  }
 
}

Callbacks.java

?
1
2
3
4
5
6
public class Callbacks {
  public static void main(String[] args) {
    Callee1 callee1 = new Callee1();
    callee1.increment();
  }
}

Callbacks 是一個測試客戶端類,沒啥好說的,直接看上面的代碼。

2.3.2 回調初試

上面的普通調用也沒啥好說的,因為這對于一個正常的 Java 程序員來說都應該是想都不用想就可以搞定的事情。

現在如果要構成回調,那么對于程序的結構或是邏輯的思維上都不可能只有一個被調用者(被回調的對象 Callee1),還需要一個調用者對象。調用者可以像下面這樣來編寫:

Caller.java

?
1
2
3
4
5
6
7
8
9
10
11
12
class Caller {
 
  private Incrementable callbackReference;
 
  public Caller(Incrementable _callbackReference) {
    callbackReference = _callbackReference;
  }
 
  void go() {
    callbackReference.increment();
  }
}

這里 Caller 持有一個回調接口的引用 callbackReference,就像在上面說到的程序員需要持有一個項目經理的引用,這樣就可以通過這個引用來與項目經理溝通。這里的 callbackReference 也正是起到了這個作用。

現在我們來看看測試類的編寫:

Callbacks.java

?
1
2
3
4
5
6
7
public class Callbacks {
  public static void main(String[] args) {
    Callee1 callee1 = new Callee1();   
    Caller caller1 = new Caller(callee1);
    caller1.go();
  }
}

對于到目前為止的程序代碼,完全可以對比上面項目經理安排程序員調研技術難題的代碼。有異曲同工之妙。

2.3.3 閉包回調

相比于正常的回調,閉包回調的核心自然是在于閉包,也就是對作用域的控制。
現在假設有一個用戶(其他程序員)自定義了一個 MyInCrement 類,同時包含了一個 increment 的方法。如下:

?
1
2
3
4
5
6
7
8
9
10
class MyInCrement {
 
  public void increment() {
    System.out.println("MyCrement.increment");
  }
 
  static void f(MyInCrement increment) {
    increment.increment();
  }
}

另外有一個類 Callee2 繼承自上面這個類:

?
1
2
3
4
5
6
7
8
9
10
class Callee2 extends MyInCrement {
 
  private int i = 0;
 
  public void increment() {
    super.increment();
    i++;
    System.out.println(i);
  }
}

顯而易見這里如果要調用 increment() 方法,就變成了一般的函數調用了。所以這里我們需要修改上面的 Callee2 類,修改的目標就是讓 Callee2 類可以兼容 MyInCrement 類的 increment() 方法和 Incrementable 的 increment() 方法。修改后:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Callee2 extends MyInCrement {
 
  private int i = 0;
 
  public void increment() {
    super.increment();
    i++;
    System.out.println(i);
  }
 
  private class Closure implements Incrementable {
 
    @Override
    public void increment() {
      Callee2.this.increment();
    }
  }
 
  Incrementable getCallbackReference() {
    return new Closure();
  }
}

注意,這里的 Closure 類是一個私有的類,這是一個閉包的要素。因為 Closure 類是私有的,那么就要有一個對外開放的接口,用來對 Closure 對象的操作,這里就是上面的 getCallbackReference() 方法。 Caller 類則沒有改變。
對于測試客戶端就直接看代碼吧:

?
1
2
3
4
5
6
7
public class Callbacks {
  public static void main(String[] args) {   
    Callee2 callee2 = new Callee2();
    Caller caller2 = new Caller(callee2.getCallbackReference());
    caller2.go();
  }
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 7777奇米 | 性色xxx | 国产91一区二区在线播放不卡 | 国产欧美一区二区成人影院 | 亚洲性爱区 | 日韩欧美一区二区在线观看 | 欧洲破处 | 按摩椅play啊太快了h | 91精品国产综合久久香蕉 | 国产另类视频一区二区三区 | 羞羞在线观看 | 99在线观看视频免费精品9 | 给我免费的视频在线观看 | 免费精品99久久国产综合精品 | 日产乱码卡1卡2卡三卡四在线 | 国产精品久久久久久久久免费hd | 免费aⅴ在线| 亚洲午夜久久久久久91 | 日韩欧美中文字幕一区二区三区 | 国产欧美一区二区三区久久 | 午夜亚洲WWW湿好爽 午夜想想爱午夜剧场 | 亚洲人成影院午夜网站 | 九九精品视频在线观看九九 | 99热自拍| 国语第一次处破女 | 91真人毛片一级在线播放 | 特级毛片全部免费播放器 | 国产麻豆精品视频 | 91久久综合 | 无码任你躁久久久久久久 | 久久国产乱子伦精品免费不卡 | 精品国产三级av在线 | 亚欧成人中文字幕一区 | 欧美va在线观看 | 国产成人在线播放视频 | 日韩爱爱 | 男人扒开女人下身添 | 好看的亚洲视频 | 欧美成狂野欧美在线观看 | 99热免费在线观看 | 美女任你模 |