html5中文学习网

您的位置: 首页 > 网络编程 > java教程 » 正文

详解Java的回调机制_java_

[ ] 已经帮助:人解决问题

模块之间总是存在这一定的接口,从调用方式上看,可以分为三类:同步调用、回调和异步调用。下面着重详解回调机制。BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

1. 概述BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

Java 中的回调机制是一个比较常见的机制,只是有可能在你的程序中使用得比较少,在一些大型的框架中回调机制随处可见。本文就通过一些具体的实例,慢慢走近 Java 的回调机制。BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

2.回调BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

所谓回调:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法。实际在使用的时候,也会有不同的回调形式,比如下面的这几种。BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

2.1 同步回调BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

这里我假设这样的一种情况。 BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

A 公司的总监 B 跟他的下属(项目经理 C)说要做一个调研,不过不用 C 自己亲力亲为。可以让经理 C 去安排他下面的程序员 D 去完成。经理 C 找到了程序员 D,并告诉他,现在要完成一个调研任务。并且把调研的结果告诉经理 C。如果有问题,还是要继续的。 因为这里是 C 让 D 去做一件事情,之后 D 还是要将结果与 C 进行沟通。这样就是回调的模型了。下面是一般回调的类图: BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

BYvHTML5中文学习网 - HTML5先行者学习网

首先我们要有一个回调的接口 CallbackInterface BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

CallbackInterface.javaBYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

public interface CallbackInterface {  public boolean check(int result);}

背景里,程序员 D 是要将结果与项目经理 C 进行沟通的,所以这里项目经理需要实现上面的回调接口: BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

Manager.javaBYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

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 持有这个接口就可以了。如下: BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

Programmer.javaBYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

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 测试: BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

Boss.javaBYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

public class Boss {  public static void main(String[] args) {    Manager manager = new Manager(new Programmer());    manager.entrust();  }}

运行结果:BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

Manager 正在为 Programmer 安排工作BYvHTML5中文学习网 - HTML5先行者学习网
第 1 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
第 2 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
第 3 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
第 4 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
第 5 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
调研任务结束BYvHTML5中文学习网 - HTML5先行者学习网
为 Programmer 安排工作已经完成,Manager 做其他的事情去了。BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

2.2 异步回调BYvHTML5中文学习网 - HTML5先行者学习网

还是上面的例子,你的项目经理不可能要一直等你调研的结果。而是把这个任务交给你之后,他就不管了,他做他的,你做你的。所以,这里需要对回调的函数进行异步处理。 BYvHTML5中文学习网 - HTML5先行者学习网
所以,这里我们需要修改 Programmer 类的代码,修改如下: BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

Programmer.javaBYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

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("调研任务结束");    }  }}

运行结果:BYvHTML5中文学习网 - HTML5先行者学习网

Manager 正在为 Programmer 安排工作BYvHTML5中文学习网 - HTML5先行者学习网
为 Programmer 安排工作已经完成,Manager 做其他的事情去了。BYvHTML5中文学习网 - HTML5先行者学习网
第 1 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
第 2 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
第 3 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
第 4 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
第 5 次研究的结果BYvHTML5中文学习网 - HTML5先行者学习网
调研任务结束BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

2.3 闭包与回调BYvHTML5中文学习网 - HTML5先行者学习网

闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。BYvHTML5中文学习网 - HTML5先行者学习网

2.3.1 普通调用BYvHTML5中文学习网 - HTML5先行者学习网

首先,我们可以看看在正常情况下的调用是怎么进行的。 BYvHTML5中文学习网 - HTML5先行者学习网
Incrementable.javaBYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

interface Incrementable {  void increment();}

这是一个普通的接口(在普通调用里只是普通接口,在回调中就是回调接口,这一点应该很好理解吧)。BYvHTML5中文学习网 - HTML5先行者学习网

Callee1.javaBYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

class Callee1 implements Incrementable {  private int i = 0;  @Override  public void increment() {    i++;    System.out.println(i);  }}

Callbacks.javaBYvHTML5中文学习网 - HTML5先行者学习网

public class Callbacks {  public static void main(String[] args) {    Callee1 callee1 = new Callee1();    callee1.increment();  }}

Callbacks 是一个测试客户端类,没啥好说的,直接看上面的代码。BYvHTML5中文学习网 - HTML5先行者学习网

2.3.2 回调初试BYvHTML5中文学习网 - HTML5先行者学习网

上面的普通调用也没啥好说的,因为这对于一个正常的 Java 程序员来说都应该是想都不用想就可以搞定的事情。 BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

现在如果要构成回调,那么对于程序的结构或是逻辑的思维上都不可能只有一个被调用者(被回调的对象 Callee1),还需要一个调用者对象。调用者可以像下面这样来编写: BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

Caller.javaBYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

class Caller {  private Incrementable callbackReference;  public Caller(Incrementable _callbackReference) {    callbackReference = _callbackReference;  }  void go() {    callbackReference.increment();  }}

这里 Caller 持有一个回调接口的引用 callbackReference,就像在上面说到的程序员需要持有一个项目经理的引用,这样就可以通过这个引用来与项目经理沟通。这里的 callbackReference 也正是起到了这个作用。 BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

现在我们来看看测试类的编写: BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

Callbacks.javaBYvHTML5中文学习网 - HTML5先行者学习网

public class Callbacks {  public static void main(String[] args) {    Callee1 callee1 = new Callee1();        Caller caller1 = new Caller(callee1);    caller1.go();  }}

对于到目前为止的程序代码,完全可以对比上面项目经理安排程序员调研技术难题的代码。有异曲同工之妙。BYvHTML5中文学习网 - HTML5先行者学习网

2.3.3 闭包回调BYvHTML5中文学习网 - HTML5先行者学习网

相比于正常的回调,闭包回调的核心自然是在于闭包,也就是对作用域的控制。 BYvHTML5中文学习网 - HTML5先行者学习网
现在假设有一个用户(其他程序员)自定义了一个 MyInCrement 类,同时包含了一个 increment 的方法。如下:BYvHTML5中文学习网 - HTML5先行者学习网

class MyInCrement {  public void increment() {    System.out.println("MyCrement.increment");  }  static void f(MyInCrement increment) {    increment.increment();  }}

另外有一个类 Callee2 继承自上面这个类:BYvHTML5中文学习网 - HTML5先行者学习网

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() 方法。修改后:BYvHTML5中文学习网 - HTML5先行者学习网

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 类则没有改变。 BYvHTML5中文学习网 - HTML5先行者学习网
对于测试客户端就直接看代码吧:BYvHTML5中文学习网 - HTML5先行者学习网
BYvHTML5中文学习网 - HTML5先行者学习网

public class Callbacks {  public static void main(String[] args) {        Callee2 callee2 = new Callee2();    Caller caller2 = new Caller(callee2.getCallbackReference());    caller2.go();  }}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。BYvHTML5中文学习网 - HTML5先行者学习网

(责任编辑:)
推荐书籍
推荐资讯
关于HTML5先行者 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助