文档章节

Java回调函数使用和剖析

万里虎
 万里虎
发布于 2013/01/19 10:10
字数 2074
阅读 2900
收藏 25
点赞 1
评论 2

其实:回调就是该函数写在高层,低层通过一个函数指针保存这个函数,在某个事件(通知)的触发下,低层通过该函数指针调用高层那个函数。

C语言中回调函数解释:

回调函数(   Callback Function)是怎样一种函数呢?

函数是用来被调用的,我们调用函数的方法有两种:

l         直接调用:在函数   A的函数体里通过书写函数   B的函数名来调用之,使内存中对应函数   B的代码得以执行。这里,   A称为“主叫函数”(   Caller),   B称为“被叫函数”(   Callee)。

l         间接调用:在函数   A的函数体里并不出现函数   B的函数名,而是使用指向函数   B的函数指针   p来使内存中属于函数   B的代码片断得以执行——听起来很酷,是吧。

比起直接调用来,间接调用的确麻烦,那为什么还要使用间接调用呢?原因很简单——直接调用把函数名都写进函数体了,经过编译器那么一编译,板上钉钉,   A注定调用的是   B了,这样的程序只能按照程序员事先设计好的流程执行下去,太呆板了。此时,间接调用的巨大灵活性就显现出来了。想一想,如果   p是函数   A的一个参数(参数是变量,是变量就可以变吗!),那么程序的最终用户完全可以通过操作来改变   p的指向——这样,   A在通过   p调用函数的时候就有机会调用到不同的函数,这样程序的实用性和扩展性就强多了。

   在WINDOWS中,程序员想让系统DLL调用自己编写的一个方法,于是利用DLL当中回调函数(CALLBACK)的接口来编写程序,使它调用,这个就称为回调。在调用接口时,需要严格的按照定义的参数和方法调用,并且需要处理函数的异步,否则会导致程序的崩溃。这样的解释似乎还是比较难懂,这里举个简单的例子,程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序。程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法。目的达到。在C/C++中,要用回调函数,被掉函数需要告诉调用者自己的指针地址,但在JAVA中没有指针,怎么办?我们可以通过接口(interface)来实现定义回调函数。

  正常情况下开发人员使用已经定义好的API,这个过程叫Call。但是有时这样不能满足需求,就需要程序员注册自己的程序,然后让事先定义好多API在合适的时候调用注册的方法,这叫CallBack。

“通常大家说的回调函数一般就是按照别人(李四)的定好的接口规范写等待别人(张三)调用的函数,在C语言中,回调函数通常通过函数指针来传递;在Java中,通常就是编写另外一个类或类库的人(李四)规定一个接口,然后你(张三)来实现这个接口,然后把这个实现类的一个对象作为参数传给别人的程序,别人的程序必要时就会通过那个接口来调用你编写的函数。

    使用技巧:定一个接口,在接口中声明我们想调用的方法。

                    在另一个方法中注册刚定义的回调接口

第一步:定义回调接口

 

 

?    

package com.callback;

 

/**

 *           @since 2012-02-02

 * @desc 定义回调接口

 */

public interface CallBackInterface {

 

    public void doSome(); 

     

    public void exectueMethod();

}

 

第二步:李四编写的程序

 

?    

package com.callback;

 

/**

 *           @since 2012-02-02

 * @desc 李四

 */

public class MethodB {

 

    public double getTime(CallBackInterface callBack) {

        long start = System.currentTimeMillis();

        callBack.exectueMethod();

        long end = System.currentTimeMillis();

        System.out.println("cost time=" + (end - start));

        return end - start;

    }

}

  第三步:张三实现李四规定的接口

?    

package com.callback;

 

/**

 *           @since 2012-02-02

 * @desc 张三

 */

public class MethodA {

 

    public static void main(String args[]){

        MethodB b=new MethodB();

        //返回值d只和MethodB有关,和接口中方法的返回值无关

        double d=b.getTime(new CallBackInterface() {

             

            //张三实现了李四定义的接口

            public void exectueMethod() {

                new MethodA().testMethod();

            }

             

            @Override

            public void doSome() {

                 

            }

        });

        System.out.println("d="+d);

    }

     

    public void testMethod(){

        for(int i=0;i<10000;i++){

            System.out.print("");

        }

    }

}

  输出结果:

cost time=31
d=31.0

理解“回调函数” 

所谓回调,就是客户程序CLIENT调用服务程序SERVER中的某个函数SA,然后SERVER又在某个时候反过来调用CLIENT中的某个函数CB,对于CLIENT来说,这个CB便叫做回调函数。例如Win32下的窗口过程函数就是一个典型的回调函数。 
一般说来,CLIENT不会自己调用CB,CLIENT提供CB的目的就是让SERVER来调用它,而且是CLIENT不得不提供。由于SERVER并不知道CLIENT提供的CB叫甚名谁,所以SERVER会约定CB的接口规范(函数原型),然后由CLIENT提前通过SERVER的一个函数R告诉SERVER自己将要使用CB函数,这个过程称为回调函数的注册,R称为注册函数。Web SERVERerviCliente以及Java的RMI都用到回调机制,可以访问远程服务器程序。 

下面举个通俗的例子: 
某天,我打电话向你请教问题,当然是个难题,:),你一时想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。这个例子说明了“异步+回调”的编程模式。其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范。 
通过上面个人感觉到回调函数更多的应用就是结合异步。比如:ajax中jServer通过组件和服务器的异步通信。 

什么是回调函数 

精妙比喻:回调函数还真有点像您随身带的BP机:告诉别人号码,在它有事情时Call您 
回调用于层间协作,上层将本层函数安装在下层,这个函数就是回调,而下层在一定条件下触发回调,例如作为一个驱动,是一个底层,他在收到一个数据时,除了完成本层的处理工作外,还将进行回调,将这个数据交给上层应用层来做进一步处理,这在分层的数据通信中很普遍。 
其实回调和API非常接近,他们的共性都是跨层调用的函数。但区别是API是低层提供给高层的调用,一般这个函数对高层都是已知的;而回调正好相反,他是高层提供给底层的调用,对于低层他是未知的,必须由高层进行安装,这个安装函数其实就是一个低层提供的API,安装后低层不知道这个回调的名字,但它通过一个函数指针来保存这个回调,在需要调用时,只需引用这个函数指针和相关的参数指针。

其实:回调就是该函数写在高层,低层通过一个函数指针保存这个函数,在某个事件的触发下,低层通过该函数指针调用高层那个函数。

 

【参考】

 

http://blog.csdn.net/sweetwxh/article/details/2067139

 

http://liutiemeng.blog.51cto.com/120361/18874

 

http://kidult.iteye.com/blog/148982

 

需要技术咨询或技术外包请联系我:

【个人站点-万里虎】http://www.bravetiger.cn/

【QQ】623277008 

【OSC众包服务产品】https://zb.oschina.net/market/opus/855386_330

【新博客】http://www.cnblogs.com/kenshinobiy/

本文转载自:http://www.cnblogs.com/wangchenyang/archive/2011/08/16/2140744.html

共有 人打赏支持
万里虎
粉丝 43
博文 100
码字总数 27724
作品 0
海淀
CTO(技术副总裁)
加载中

评论(2)

风语安然
风语安然
多谢分享
j
jsphper
学习了
python中jpype回调某个jar包中函数返回值类型为其父类,如何获取其子类

如图所示,我在python里面使用jpype回调java第三方包里面的某个函数,返回类型一直为DBApiLayer这个对象类型,但是我在python里面需要获取到的是DB这个对象类型,我看了下我回调方法返回类型...

一眼000 ⋅ 04/25 ⋅ 0

IOC/AOP工具 - jBeanBox

jBeanBox是一个微形但功能较齐全的IOC/AOP工具适用于JAVA7+,利用了Java的初始化块实现的Java配置代替XML。jBeanBox采用Apache License 2.0开源协议。 其他一些IOC/AOP框架的问题: 1)Sprin...

yong9981 ⋅ 2016/07/25 ⋅ 14

python中jpype回调某个jar包中函数返回值类型为其子类,如何获取其父类

如图所示,我在python里面使用jpype回调java第三方包里面的某个函数,返回类型一直为DBApiLayer这个对象类型,但是我在python里面需要获取到的是DB这个对象类型,我看了下我回调方法返回类型...

一眼000 ⋅ 05/02 ⋅ 0

阿里年薪50WJAVA工程师转大数据学习路线!

大数据有两个方向,一个是偏计算机的,另一个是偏经济的。你学过Java,所以你可以偏将计算机的。 Java程序员想转大数据可行吗?Java是全世界使用人数最多的编程语言。不少程序员选择Java做为...

JAVA丶学习 ⋅ 04/25 ⋅ 0

swt browser控件与java交互

1、java调用browser页面里的js [javascript] view plain copy final Browser browser = new Browser(shell, SWT.FILL_WINDING); browser.evaluate("fun()");//fun是一个定义好的js函数 2、j......

xiaomin0322 ⋅ 06/12 ⋅ 0

大型互联网架构必备技术——性能调优专题

性能调优 深入内核,直击故障 ,拒绝蒙圈 性能优化如何理解 1、性能基准 2、什么是性能优化 3、衡量标准 JVM调优 1、Jvm虚拟机内存剖析 2、垃圾收集器 3、实战调优案例与解决方案 4、Jvm运行...

Java高级架构 ⋅ 04/15 ⋅ 0

【目录导航】JAVA零基础进阶之路

【JAVA零基础入门系列】(已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day6 Java字符串 Day7 Java输入与输出...

MFrank ⋅ 06/21 ⋅ 0

Spring之jdbc Template实现CRUD操作

Spring为各种持久化技术都提供了简单操作的模板回调。比如jdbc、hibernate、Mybatis以及JPA等。 这里我们就以JDBC为例,看看JDBC template怎么实现CRUD操作。 JdbcTemplate主要提供以下几类方...

Java攻城玩家 ⋅ 05/31 ⋅ 0

02、Java的lambda表达式和JavaScript的箭头函数

[toc] 前言 在JDK8和ES6的语言发展中,在Java的lambda表达式和JavaScript的箭头函数这两者有着千丝万缕的联系;本次试图通过这篇文章弄懂上面的两个“语法糖”。 简介 Lambda 表达式来源于 ...

weir_will ⋅ 06/14 ⋅ 0

Java开发者不会这些永远都只能是三流程序员,细数一下你是不是?

源码系列 手写spring mvc框架 基于Spring JDBC手写ORM框架 实现自己的MyBatis Spring AOP实战之源码分析 Spring IOC高级特性应用分析 ORM框架底层实现原理剖析 手写Spring MVC框架实现 手把手...

美的让人心动 ⋅ 04/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Jenkins实践3 之脚本

#!/bin/sh# export PROJ_PATH=项目路径# export TOMCAT_PATH=tomcat路径killTomcat(){pid=`ps -ef | grep tomcat | grep java|awk '{print $2}'`echo "tom...

晨猫 ⋅ 今天 ⋅ 0

Spring Bean的生命周期

前言 Spring Bean 的生命周期在整个 Spring 中占有很重要的位置,掌握这些可以加深对 Spring 的理解。 首先看下生命周期图: 再谈生命周期之前有一点需要先明确: Spring 只帮我们管理单例模...

素雷 ⋅ 今天 ⋅ 0

zblog2.3版本的asp系统是否可以超越卢松松博客的流量[图]

最近访问zblog官网,发现zlbog-asp2.3版本已经进入测试阶段了,虽然正式版还没有发布,想必也不久了。那么作为aps纵横江湖十多年的今天,blog2.2版本应该已经成熟了,为什么还要发布这个2.3...

原创小博客 ⋅ 今天 ⋅ 0

聊聊spring cloud的HystrixCircuitBreakerConfiguration

序 本文主要研究一下spring cloud的HystrixCircuitBreakerConfiguration HystrixCircuitBreakerConfiguration spring-cloud-netflix-core-2.0.0.RELEASE-sources.jar!/org/springframework/......

go4it ⋅ 今天 ⋅ 0

二分查找

二分查找,也称折半查找、二分搜索,是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于...

人觉非常君 ⋅ 今天 ⋅ 0

VS中使用X64汇编

需要注意的是,在X86项目中,可以使用__asm{}来嵌入汇编代码,但是在X64项目中,再也不能使用__asm{}来编写嵌入式汇编程序了,必须使用专门的.asm汇编文件来编写相应的汇编代码,然后在其它地...

simpower ⋅ 今天 ⋅ 0

ThreadPoolExecutor

ThreadPoolExecutor public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, ......

4rnold ⋅ 昨天 ⋅ 0

Java正无穷大、负无穷大以及NaN

问题来源:用Java代码写了一个计算公式,包含除法和对数和取反,在页面上出现了-infinity,不知道这是什么问题,网上找答案才明白意思是负的无穷大。 思考:为什么会出现这种情况呢?这是哪里...

young_chen ⋅ 昨天 ⋅ 0

前台对中文编码,后台解码

前台:encodeURI(sbzt) 后台:String param = URLDecoder.decode(sbzt,"UTF-8");

west_coast ⋅ 昨天 ⋅ 0

实验楼—MySQL基础课程-挑战3实验报告

按照文档要求创建数据库 sudo sercice mysql startwget http://labfile.oss.aliyuncs.com/courses/9/createdb2.sqlvim /home/shiyanlou/createdb2.sql#查看下数据库代码 代码创建了grade......

zhangjin7 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部