回调函数

谈到回调,我们得先从回调函数说起,什么叫回调函数呢?

回调函数是什么?

百度百科的解释:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外一方调用的,用于对该事件或条件进行响应。

接着,我们从下图简单说明一下回调函数。

已知图形上面三种模块,此时标号2能称为回调函数吗?

答案:不能,只有当标号2函数作为参数传递给标号3函数使用时,才能称为回调函数。

再比如,人(类似函数声明)、老王(类似函数定义)、学校(类似调用方)三个概念,某学校需要招聘人当教师,这时老王去应聘,由于老王具有出色的教导能力,学校聘用老王作为高级教师。被学校成功聘用的老王,此时才能称为高级教师(类似回调函数),否则他还只是老王这一个身份,而不能称为高级教师。

回调函数的机制:

(1)定义一个回调函数;

(2)提供函数实现的一方在初始化时候,将回调函数的函数指针注册给调用者;

(3)当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。

回调函数通常与原始调用者处于同一层次,如图所示:

为什么使用回调函数?

因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。

如果想知道回调函数在实际中有什么作用,先假设有这样一种情况,我们要编写一个库,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排序、shake排序等等,但为使库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,想让库可用于多种数据类型(int、float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。
回调可用于通知机制,例如,有时要在程序中设置一个计时器,每到一定时间,程序会得到相应的通知,但通知机制的实现者对我们的程序一无所知。而此时,就需有一个特定原型的函数指针,用这个指针来进行回调,来通知我们的程序事件已经发生。实际上,SetTimer() API使用了一个回调函数来通知计时器,而且,万一没有提供回调函数,它还会把一个消息发往程序的消息队列。
      另一个使用回调机制的API函数是EnumWindow(),它枚举屏幕上所有的顶层窗口,为每个窗口调用一个程序提供的函数,并传递窗口的处理程序。如果被调用者返回一个值,就继续进行迭代,否则,退出。EnumWindow()并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为基于返回值,它将继续执行或退出。

如何使用回调函数?

使用回调函数,我们需要做三件事:

1、声明函数模型

2、定义函数体

3、将回调函数作为参数传递给满足格式的函数,以便系统调用。

例1:一段C语言代码

#include <iostream>using namespace std;

// 1、声明typedef void (*PF)();// 2、定义void func(){  cout << "func" << endl;}

void caller( PF pf){  pf();}

int main(){  PF p = func;  // 3、函数作为参数传递  caller(p);

  system("pause");

  return 0;}

例2:C#代码
using System;using System.Runtime.InteropServices;// 1、函数声明public delegate bool CallBack(int hwnd, int lParam);

public class EnumReportApp{    [DllImport("user32")]    public static extern int EnumWindows(CallBack x, int y); 

    public static void Main()     {        // 3、函数作为参数传递        CallBack myCallBack = new CallBack(EnumReportApp.Report);        EnumWindows(myCallBack, 0);    }    // 2、函数定义    public static bool Report(int hwnd, int lParam)    {         Console.Write("Window handle is ");        Console.WriteLine(hwnd);        return true;    }}

从回调函数的使用说明中,我们可以将分为两部分:协议和协议的调用

1、协议规范(函数声明)

2、协议实现(函数定义)

3、调用协议(函数作为参数传递,使用)

接口回调

Java是一门面向对象语言,一切皆对象,因此在Java中不存在回调函数这一说法的。由于Java的一切皆对象性质,从而将回调函数这个特性提升到了接口回调。

接口回调是什么?

接口回调:可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。

从概念可以看出,接口回调是指一个使用过程,并强调是关于对象功能的使用过程,既然是功能,功能一般就对应着方法体(函数),因此它同样满足与回调函数相似的模型。

(1)接口的定义

(2)接口的实现

(3)调用接口

将(2)的引用(地址)传递给(3),然后(3)调用(2)中的方法,这一过程称为对象功能的接口回调。

接口回调与回调函数不同点:接口回调注重的是过程,而回调函数强调的是函数(实体)。

接口回调与回调函数相同点:都是将自身地址传递给调用者,让调用者根据地址调用相关的方法。

关于回调的个人简单理解就是:将你本身的地址传给我,我根据你的地址去调用你。

接口回调的机制与回调函数的机制类似:

(1)定义一个接口;

(2)提供接口实现的一方在初始化的时候,将接口回调的引用注册给调用者;

(3)当特定的事件或条件发生的时候,调用者使用引用调用实现的接口方法对事件进行处理。

接口回调的好处与回调函数的使用类似,在此就不重复介绍。

如何使用接口回调?

接口回调,我将其分为两种方式,一种推模式,一种为拉模式。

推模式

接口回调的推模式,指的是,甲方主动将其地址推送给调用者。比如下例:

接口:

public interface GasListener{    public void offerGas(String msg);}

接口实现的甲方:

public class GasCompany implements GasListener{        public void advertiseTo(IndoorsMan man)    {        System.out.println("煤气公司:这是我们的联系方式,欢迎来电!");        man.setListener(this);    }    @Override    public void offerGas(String msg)    {        System.out.println("煤气公司接收的订单:"+msg);    }}

调用者:

public class IndoorsMan {    GasListener gListener;    public void prepareCook()    {        System.out.println("宅男:准备下厨做几个花式大菜!");        System.out.println("宅男:进厨房,烧菜...");        System.out.println("宅男:刚开火,就发现煤气不足,没办法,只能打电话叫煤气。");        gListener.offerGas("宅男:送一瓶煤气过来!");    }        public void setListener(GasListener gListener)    {        this.gListener = gListener;    }}

测试:

public class Test{    public static void main(String[] args)    {        IndoorsMan man = new IndoorsMan();        GasCompany company = new GasCompany();

        company.advertiseTo(man);        man.prepareCook();    }            }

GasCompany公司在打广告时,就主动把自身信息告诉了IndoorsMan,当IndoorsMan发现煤气不足这一事件发生时,IndoorsMan就根据接口的引用调用GasCompany服务。

拉模式
接口回调的拉模式,指的是,调用者自己主动获取甲方的信息。

调用者

public class IndoorsMan {    GasListener gListener;    public void prepareCook()    {        System.out.println("宅男:准备下厨做几个花式大菜!");        System.out.println("宅男:进厨房,烧菜...");        System.out.println("宅男:刚开火,就发现煤气不足,没办法,只能打电话叫煤气。");        gListener.offerGas("宅男:送一瓶煤气过来!");    }        public void setListener(GasListener gListener)    {        this.gListener = gListener;    }    public void configureGas()    {        // 主动获取甲方信息        setListener(new GasListener()        {                        @Override            public void offerGas(String msg)            {                System.out.println("下单内容:"+msg);            }        });    }    }

测试
public class Test{    public static void main(String[] args)    {        IndoorsMan man = new IndoorsMan();        man.configureGas();        man.prepareCook();    }            }

再比如,使用线程Thread时,常常会在构建线程对象时,主动获取Runnable接口的实现。
public class Test{    public static void main(String[] args)    {        Thread thread = new Thread(new Runnable()        {            @Override            public void run()            {

            }        });    }            }

扩展:
接口回调机制满足观察者设计模式,观察者将自身地址注册给被观察者,当某一事件发生时,被观察者根据注册的地址调用相应的观察者。

参考:

1、回调函数和函数指针

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

3、JAVA回调机制(CallBack)详解

转载于:https://www.cnblogs.com/aoguren/p/5544865.html

回调函数、Java接口回调 总结相关推荐

  1. Java接口回调机制

    1.什么是回调? 一般来说,模块之间都存在一定的调用关系,从调用方式上看,可以分为三类同步调用.异步调用和回调. 同步调用是一种阻塞式调用,即在函数A的函数体里通过书写函数B的函数名来调用之,使内存中 ...

  2. Java接口回调,异步回调理解

    文章目录 前言 一.回调简单理解 二.Java中用接口实现回调 1.实现接口回调 1.1同步回调 1.2 异步回调 2.为啥要用接口实现 3.关于接口(基础) 总结 前言 本文是作者在学习接口回调时看 ...

  3. Java接口回调详解

    一.产生接口回调的场景 在现实生活中,产生接口回调的场景很简单,比如我主动叫你帮我做一件事,然后你做完这件事之后会通知我,"通知我"这个动作就是接口回调的动作.接口回调重在理解思就 ...

  4. 【Android 高性能音频】AAudio 音频流 数据回调细节 ( 数据回调函数优先级 | 数据回调函数 | 采样率 | 采样数 | 缓冲区调整 | 线程不安全 )

    文章目录 I . 数据回调函数优先级 II . 数据回调函数 相关内容 III . 采样率 处理细节 IV . 数据回调函数 每次 采样个数 numFrames V . 数据回调函数 缓冲区 ( AA ...

  5. 【Android 高性能音频】AAudio 音频流 PCM 采样 的 采样 缓冲 播放 的 连续机制 ( 数据回调机制 | 数据回调函数指针 | 实现数据回调函数 | 设置数据回调函数 )

    文章目录 I . AAudio 音频流 采样 缓冲 播放 的连续机制 II . AAudio 音频流 数据回调函数 函数指针类型定义 III . AAudio 音频流 数据回调函数 实现 IV . A ...

  6. 【cocos2d-x从c++到js】12:回调函数1——按键回调

    回调函数是界面交互和接入各种第三方SDK的关键所在,因为回调函数的C++代码是不能自动生成的,一切的一切,都需要手写完成. 比较不错的是,Cocos2d-x引擎对于回调函数提供了完整的包装机制.我们所 ...

  7. 关于js的回调函数,同步回调与异步回调

    回调定义 刚开始学习javascript时,对回调函数的理解仅仅停留在知道定义阶段.什么是回调函数? 就是将一个函数作为参数传递给另一个函数,作为参数的这个函数就是回调函数. 至于为什么要用到回调函数 ...

  8. c语言timer linux 回调函数_SetTimer 与回调函数

    在控制台应用程序中,SetTimer的函数原型为: UINT_PTR SetTimer( HWND,// handle to window UINT_PTR,// timer identifier U ...

  9. 通达信交易接口函数Java接口抽象法

    通达信交易接口函数Java接口抽象法,在package cn.itcast.day10.demo01:在任何版本的Java中,接口都能定义抽象方法.

最新文章

  1. android 点击图片事件,android图文混排点击事件
  2. android view 渐变动画,Android自定义view渐变圆形动画
  3. 密码学系列之:feistel cipher
  4. 传统公司部署OpenStack(t版)简易介绍(三)——Glance组件部署
  5. 中国重汽微服务管理_干货 | 微服务架构下 Spring Cloud OAuth2 通用权限管理系统
  6. Keras学习---MLP和CNN模型建立篇
  7. redis持久化RDB与AOF
  8. 不规则裁剪图片css,在css中将div剪裁成不规则形状的方法
  9. 笔记本电脑显示打印机服务器关闭,电脑打印机服务能设定自动关闭吗
  10. 解决鼠标右键失效(响应极慢)
  11. 什么是PMU(PMIC)
  12. ready与onload的区别
  13. JAVA高级面试题汇总及答案
  14. 如何获得最新的太阳神三国杀 自己Qt编译
  15. LearnOpenGL->光照->投光物/多光源
  16. chrome清除当前网页缓存和禁用js
  17. 如何检查内存泄露问题
  18. [转载]从100PV到1亿级PV网站架构演变
  19. 自动化测试难?WPS的UI自动化落地方案甩给你
  20. BWT(Burrows-Wheelter Transform)算法

热门文章

  1. Oracle表空间查询及扩充表空间
  2. VMware 修改虚拟机网络_虚拟机问题解决
  3. java 获取_java获取类的信息
  4. 蔡氏电路matlab程序,蔡氏电路matlab仿真报告
  5. php删除文件指令,php – Symfony cache:清除命令更改文件夹所有者
  6. 一周一论文(翻译)—— [PVLDB 12] Distributed GraphLab A Framework for Machine Learning 分布式机器学习图计算框架
  7. python按行求和_Python第一篇:对3个Excel文件进行整合
  8. c语言最大公约数和最小公倍数_五年级数学最大公因数最小公倍数 练习
  9. T-SQL编程基础-基本语法
  10. centos6.8防火墙模块未加载