Java 消息机制之回调详解
来源:互联网 发布:ca证书检测网络未连接 编辑:程序博客网 时间:2024/06/05 19:59
1. 概述
Java 中的回调机制是一个比较常见的机制,只是有可能在你的程序中使用得比较少,在一些大型的框架中回调机制随处可见。而在之前的博文《Java设计模式——观察者模式》及 Android 中对 ListView 的相关操作也有回调身影。本文就通过一些具体的实例,慢慢走近 Java 的回调机制。
2. 版权说明
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
本文作者:Q-WHai
发表日期: 2016年4月24日
本文链接:http://blog.csdn.net/lemon_tree12138/article/details/51231841
来源:CSDN
更多内容:分类 >> Thinking in java
3. 目录
- 概述
- 版权说明
- 目录
- 回调
- 1 同步回调
- 2 异步回调
- 3 闭包与回调
- 31 普通调用
- 32 回调初试
- 33 闭包回调
- Ref
4. 回调
所谓回调:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法。实际在使用的时候,也会有不同的回调形式,比如下面的这几种。
4.1 同步回调
这里我假设这样的一种情况。
A 公司的总监 B 跟他的下属(项目经理 C)说要做一个调研,不过不用 C 自己亲力亲为。可以让经理 C 去安排他下面的程序员 D 去完成。
经理 C 找到了程序员 D,并告诉他,现在要完成一个调研任务。并且把调研的结果告诉经理 C。如果有问题,还是要继续的。
因为这里是 C 让 D 去做一件事情,之后 D 还是要将结果与 C 进行沟通。这样就是回调的模型了。下面是一般回调的类图:
首先我们要有一个回调的接口 CallbackInterface
CallbackInterface.java
public interface CallbackInterface { public boolean check(int result);}
背景里,程序员 D 是要将结果与项目经理 C 进行沟通的,所以这里项目经理需要实现上面的回调接口:
Manager.java
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
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
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 做其他的事情去了。
4.2 异步回调
还是上面的例子,你的项目经理不可能要一直等你调研的结果。而是把这个任务交给你之后,他就不管了,他做他的,你做你的。所以,这里需要对回调的函数进行异步处理。
所以,这里我们需要修改 Programmer 类的代码,修改如下:
Programmer.java
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 次研究的结果调研任务结束
4.3 闭包与回调
闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。
这一部分的内容主要是参见于《Java 编程思想》一书,具体细节大家可以参见此书。
可能很多人在阅读《Java 编程思想》的时候有一些小迷糊,迷糊的原因可能多种多样。只是书中的代码展示部分的确有一些头痛,没有什么结构可言(这个只是我个人的阅读习惯,无关书籍本身的经典性),所以阅读起来不是很给力吧。下面就我阅读时的一个小总结。
4.3.1 普通调用
首先,我们可以看看在正常情况下的调用是怎么进行的。
Incrementable.java
interface Incrementable { void increment();}
这是一个普通的接口(在普通调用里只是普通接口,在回调中就是回调接口,这一点应该很好理解吧)。
Callee1.java
class Callee1 implements Incrementable { private int i = 0; @Override public void increment() { i++; System.out.println(i); }}
Callbacks.java
public class Callbacks { public static void main(String[] args) { Callee1 callee1 = new Callee1(); callee1.increment(); }}
Callbacks 是一个测试客户端类,没啥好说的,直接看上面的代码。
4.3.2 回调初试
上面的普通调用也没啥好说的,因为这对于一个正常的 Java 程序员来说都应该是想都不用想就可以搞定的事情。
现在如果要构成回调,那么对于程序的结构或是逻辑的思维上都不可能只有一个被调用者(被回调的对象 Callee1),还需要一个调用者对象。调用者可以像下面这样来编写:
Caller.java
class Caller { private Incrementable callbackReference; public Caller(Incrementable _callbackReference) { callbackReference = _callbackReference; } void go() { callbackReference.increment(); }}
这里 Caller 持有一个回调接口的引用 callbackReference,就像在上面说到的程序员需要持有一个项目经理的引用,这样就可以通过这个引用来与项目经理沟通。这里的 callbackReference 也正是起到了这个作用。
现在我们来看看测试类的编写:
Callbacks.java
public class Callbacks { public static void main(String[] args) { Callee1 callee1 = new Callee1(); Caller caller1 = new Caller(callee1); caller1.go(); }}
对于到目前为止的程序代码,完全可以对比上面项目经理安排程序员调研技术难题的代码。有异曲同工之妙。
4.3.3 闭包回调
相比于正常的回调,闭包回调的核心自然是在于闭包,也就是对作用域的控制。
现在假设有一个用户(其他程序员)自定义了一个 MyInCrement 类,同时包含了一个 increment 的方法。如下:
class MyInCrement { public void increment() { System.out.println("MyCrement.increment"); } static void f(MyInCrement increment) { increment.increment(); }}
另外有一个类 Callee2 继承自上面这个类:
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() 方法。修改后:
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 类则没有改变。
对于测试客户端就直接看代码吧:
public class Callbacks { public static void main(String[] args) { Callee2 callee2 = new Callee2(); Caller caller2 = new Caller(callee2.getCallbackReference()); caller2.go(); }}
5. Ref
- http://blog.csdn.net/pi9nc/article/details/23169357
- http://blog.csdn.net/xiaanming/article/details/8703708/
- 《Java 编程思想》
- Java 消息机制之回调详解
- Objective-C 之 消息机制详解
- Android之Handler消息机制详解
- Looper详解--Android消息机制之4
- Looper详解--Android消息机制之4
- Android之异步消息处理机制详解
- java之模块学习-接口回调机制详解
- java回调机制详解
- Java 回调机制详解
- Java回调机制详解
- JVM详解之Java垃圾回收机制详解和调
- Windows 消息机制详解
- Windows消息机制详解
- Windows 消息机制详解
- Windows消息机制详解
- windows消息机制详解
- Android消息机制详解
- Handler消息机制详解
- OBJ-C匿名对象和封装学习笔记
- Linux内核--内存管理
- 用std::pair做Unordered_map的key(C++)
- C++笔记 如何统计程序运行时间
- 51Nod-1013-3的幂的和
- Java 消息机制之回调详解
- 几道题(hdu5671 && hdu5672 && hdu5673)
- LeetCode 139. Word Break
- hdu 1005 Number Sequence
- [Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)
- Qt Creator Plug-in Gallery
- LeetCode 225. Implement Stack using Queues
- MySQL绿色版的安装(mysql-5.6.22-win32.zip)
- 如何在Linux中查看所有正在运行的进程