深入浅出Java回调机制

 前几天看了一下Spring的部分源码,发现回调机制被大量使用,觉得有必要把Java回调机制的理解归纳总结一下,以方便在研究类似于Spring源码这样的代码时能更加得心应手。

  注:本文不想扯很多拗口的话来充场面,我的目的是希望以最简明扼要的语言将Java回调的大概机制说清楚。好了,言归正传。

  一句话,回调是一种双向调用模式,什么意思呢,就是说,被调用方在被调用时也会调用对方,这就叫回调。“If you call me, i will call back”。

  不理解?没关系,先看看这个可以说比较经典的使用回调的方式:

  class A实现接口InA ——背景1

  class A中包含一个class B的引用b ——背景2

  class B有一个参数为InA的方法test(InA a) ——背景3

  A的对象a调用B的方法传入自己,test(a) ——这一步相当于you call me

  然后b就可以在test方法中调用InA的方法 ——这一步相当于i call you back

  是不是清晰一点了?下面再来看一个完全符合这个方式模板的例子

  (PS:这个例子来源于网络,由于这个例子表现的功能极度拉风,令我感觉想想出一个超越它的例子确实比较困难,所以直接搬过来)


//相当于接口InA

public interface BoomWTC{

//获得拉登的决定

public benLaDengDecide();

// 执行轰炸世贸

public void boom();

}

//相当于class A

public class At$911 implements BoomWTC{//相当于【背景1】

private boolean decide;

private TerroristAttack ta;//相当于【背景2】

public At$911(){

Date now=new Date();

SimpleDateFormat myFmt1=new SimpleDateFormat("yy/MM/dd HH:mm");

this.dicede= myFmt.format(dt).equals("01/09/11 09:44");

this.ta=new TerroristAttack();

}

//获得拉登的决定

public boolean benLaDengDecide(){

return decide;

}

// 执行轰炸世贸

public void boom(){

ta.attack(new At$911);//class A调用class B的方法传入自己的对象,相当于【you call me】

}

}

//相当于class B

public class TerroristAttack{

public TerroristAttack(){

}

public attack(BoomWTC bmw){——这相当于【背景3】

if(bmw.benLaDengDecide()){//class B在方法中回调class A的方法,相当于【i call you back】

//let's go.........

}

}

}

  现在应该对回调有一点概念了吧。

可是问题来了,对于上面这个例子来说,看不出用回调有什么好处,直接在调用方法不就可以了,为什么要使用回调呢?

  事实上,很多需要进行回调的操作是比较费时的,被调用者进行费时操作,然后操作完之后将结果回调给调用者。看这样一个例子:


//模拟Spring中HibernateTemplate回调机制的代码

interface CallBack{

public void doCRUD();

}

public class HibernateTemplate {

public void execute(CallBack action){

getConnection();

action.doCRUD();

releaseConnection();

}

public void add(){

execute(new CallBack(){

public void doCRUD(){

System.out.println("执行add操作...");

}

});

}

public void getConnection(){

System.out.println("获得连接...");

}

public void releaseConnection(){

System.out.println("释放连接...");

}

}

  可能上面这个例子你不能一眼看出个所以然来,因为其实这里A是作为一个内部匿名类存在的。好,不要急,让我们把这个例子来重构一下:


interface CallBack{   //相当于接口InA

public void doCRUD();

}

public class A implements CallBack{//【背景1】

private B b;//【背景2】

public void doCRUD(){

System.out.println("执行add操作...");

}

public void add(){

b.execute(new A());//【you call me】

}

}

public class B{

public void execute(CallBack action){  //【背景3】

getConnection();

action.doCRUD();  //【i call you back】

releaseConnection();

}

public void getConnection(){

System.out.println("获得连接...");

}

public void releaseConnection(){

System.out.println("释放连接...");

}

}

  好了,现在就明白多了吧,完全可以转化为上面所说的回调使用方式的模板。

  现在在来看看为什么要使用回调,取得连接getConnection();是费时操作,A希望由B来进行这个费时的操作,执行完了之后通知A即可(即所谓的i call you back)。这就是这里使用回调的原因。

  在网上看到了一个比喻,觉得很形象,这里借用一下:

  你有一个复杂的问题解决不了,打电话给你的同学,你的同学说可以解决这个问题,但是需要一些时间,那么你不可能一直拿着电话在那里等,你会把你的电话号码告诉他,让他解决之后打电话通知你。回调就是体现在你的同学又反过来拨打你的号码。

  结合到前面所分析的,你打电话给你同学就是【you call me】,你同学解决完之后打电话给你就是【i call you back】。

  怎么样,现在理解了吧?

  ---------------------------------以下为更新----------------------------------

  看了有些朋友的回帖,我又思考了一下,感觉自己之前对回调作用的理解的确存在偏差。

  下面把自己整理之后的想法共享一下,如果有错误希望指出!多谢!

  先说上面这段代码,本来完全可以用模板模式来进行实现:


public abstract class B{

public void execute(){

getConnection();

doCRUD();

releaseConnection();

}

public abstract void doCRUD();

public void getConnection(){

System.out.println("获得连接...");

}

public void releaseConnection(){

System.out.println("释放连接...");

}

}

public class A extends B{

public void doCRUD(){

System.out.println("执行add操作...");

}

public void add(){

doCRUD();

}

}

public class C extends B{

public void doCRUD(){

System.out.println("执行delete操作...");

}

public void delete(){

doCRUD();

}

}

如果改为回调实现是这样的:

interface CallBack{

public void doCRUD();

}

public class HibernateTemplate {

public void execute(CallBack action){

getConnection();

action.doCRUD();

releaseConnection();

}

public void add(){

execute(new CallBack(){

public void doCRUD(){

System.out.println("执行add操作...");

}

});

}

public void delete(){

execute(new CallBack(){

public void doCRUD(){

System.out.println("执行delete操作...");

}

});

}

public void getConnection(){

System.out.println("获得连接...");

}

public void releaseConnection(){

System.out.println("释放连接...");

}

}

  可见摒弃了继承抽象类方式的回调方式更加简便灵活。不需要为了实现抽象方法而总是继承抽象类,而是只需要通过回调来增加一个方法即可,更加的直观简洁灵活。这算是回调的好处之一。

  下面再给出一个关于利用回调配合异步调用的很不错的例子

  回调接口:


public interface CallBack {

/**

* 执行回调方法

* @param objects   将处理后的结果作为参数返回给回调方法

*/

public void execute(Object... objects );

}

消息的发送者:

/**

* 这个类相当于你自己

*/

public class Local implements CallBack,Runnable{

private Remote remote;

/**

* 发送出去的消息

*/

private String message;

public Local(Remote remote, String message) {

super();

this.remote = remote;

this.message = message;

}

/**

* 发送消息

*/

public void sendMessage()

{

/**当前线程的名称**/

System.out.println(Thread.currentThread().getName());

/**创建一个新的线程发送消息**/

Thread thread = new Thread(this);

thread.start();

/**当前线程继续执行**/

System.out.println("Message has been sent by Local~!");

}

/**

* 发送消息后的回调函数

*/

public void execute(Object... objects ) {

/**打印返回的消息**/

System.out.println(objects[0]);

/**打印发送消息的线程名称**/

System.out.println(Thread.currentThread().getName());

/**中断发送消息的线程**/

Thread.interrupted();

}

public static void main(String[] args)

{

Local local = new Local(new Remote(),"Hello");

local.sendMessage();

}

public void run() {

remote.executeMessage(message, this);  //这相当于给同学打电话,打完电话之后,这个线程就可以去做其他事情了,只不过等到你的同学打回电话给你的时候你要做出响应

}

}

  消息的接收者:


/**

* 这个类相当于你的同学

*/

public class Remote {

/**

* 处理消息

* @param msg   接收的消息

* @param callBack  回调函数处理类

*/

public void executeMessage(String msg,CallBack callBack)

{

/**模拟远程类正在处理其他事情,可能需要花费许多时间**/

for(int i=0;i<1000000000;i++)

{

}

/**处理完其他事情,现在来处理消息**/

System.out.println(msg);

System.out.println("I hava executed the message by Local");

/**执行回调**/

callBack.execute(new String[]{"Nice to meet you~!"});  //这相当于同学执行完之后打电话给你

}

}

  由上面这个例子可见,回调可以作为异步调用的基础来实现异步调用。

最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-11-08 21:52:33

深入浅出Java回调机制的相关文章

深入浅出Java回调机制-(二)

前几天看了一下Spring的部分源码,发现回调机制被大量使用,觉得有必要把Java回调机制的理解归纳总结一下,以方便在研究类似于Spring源码这样的代码时能更加得心应手. 注:本文不想扯很多拗口的话来充场面,我的目的是希望以最简明扼要的语言将Java回调的大概机制说清楚.好了,言归正传. 一句话,回调是一种双向调用模式,什么意思呢,就是说,被调用方在被调用时也会调用对方,这就叫回调."If you call me, i will call back". 不理解?没关系,先看看这个可以

深入浅出: Java回调机制(异步)

什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道"就一个回调-".此时千万个草泥马飞奔而过(逃 哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉.不妨总结总结. 一.什么是回调 回调,回调.要先有调用,才有调用者和被调用者之间的回调.所以在百度百科中是这样的: 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用.回调和异步调用. 回调是一种特殊的调用,至于三种方式也有点不同. 1.同步回调,即阻塞,单向. 2.回调,即双向(类似自行车的两个齿轮)

一个经典例子让你彻彻底底理解java回调机制(一)

转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273),请尊重他人的辛勤劳动成果,谢谢 以前不理解什么叫回调,天天听人家说加一个回调方法啥的,心里想我草,什么叫回调方法啊?然后自己就在网上找啊找啊找,找了很多也不是很明白,现在知道了,所谓回调:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法,这样子说你是不是有点晕晕的,其实我刚开始也是这样不理解,看了

一个经典例子让你彻彻底底理解java回调机制

以前不理解什么叫回调,天天听人家说加一个回调方法啥的,心里想我草,什么叫回调方法啊?然后自己就在网上找啊找啊找,找了很多也不是很明白,现在知道了,所谓回调:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法,这样子说你是不是有点晕晕的,其实我刚开始也是这样不理解,看了人家说比较经典的回调方式: Class A实现接口CallBack callback--背景1 class A中包含一个class B的引用b --背景2 class B有一个参数为call

详解 JAVA的回调机制CallBack_java

序言 CallBack是回调的意思,熟悉Windows编程的人对"回调函数"这四个字一定不会陌生,但是Java程序员对它可能就不太了解了."回调函数"或者"回调方法"是软件设计与开发中一个非常重要的概念,掌握"回调函数"的思想对程序员来说(不管用哪种语言)是非常必要的. 最近学习java,接触到了回调机制(CallBack).初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBac

详解Java的回调机制_java

模块之间总是存在这一定的接口,从调用方式上看,可以分为三类:同步调用.回调和异步调用.下面着重详解回调机制. 1. 概述 Java 中的回调机制是一个比较常见的机制,只是有可能在你的程序中使用得比较少,在一些大型的框架中回调机制随处可见.本文就通过一些具体的实例,慢慢走近 Java 的回调机制. 2.回调 所谓回调:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法.实际在使用的时候,也会有不同的回调形式,比如下面的这几种. 2.1 同步回调 这里我假设

[JVM]成为JavaGC专家(1)—深入浅出Java垃圾回收机制

对于Java开发人员来说,了解垃圾回收机制(GC)有哪些好处呢?首先可以满足作为一名软件工程师的求知欲,其次,深入了解GC如何工作可以帮你写出更好的Java应用. 这仅仅代表我个人的意见,但我坚信一个精通GC的人往往是一个好的Java开发者.如果你对GC的处理过程感兴趣,说明你已经具备较大规模应用的开发经验.如果你曾经想过如何正确的选择GC算法,那意味着你已经完全理解你所开发的应用的特点.当然,我们不能以偏概全,这不能作为评价一个好的开发人员的共通标准.但是,我要说的是,深入理解GC是成为一名伟

理解Java当中的回调机制

你好,今天我要和大家分享一些东西,举例来说这个在JavaScript中用的很多.我要讲讲回调(callbacks).你知道什么时候用,怎么用这个吗?你真的理解了它在java环境中的用法了吗?当我也问我自己这些问题,这也是我开始研究这些的原因.这个背后的思想是控制反转( PS:维基百科的解释是控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.)这个范例描述了框架(framework)的工作方式,也以"好莱坞原则:

Java 异步回调机制实例解析

什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道"就一个回调-".此时千万个草泥马飞奔而过 哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉.不妨总结总结. 一.什么是回调 回调,回调.要先有调用,才有调用者和被调用者之间的回调.所以在百度百科中是这样的: 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用.回调和异步调用. 回调是一种特殊的调用,至于三种方式也有点不同. 1.同步回调,即阻塞,单向. 2.回调,即双向(类似自行车的两个齿轮).