什么是回调函数?
当前回答
“在计算机编程中,回调是对可执行代码或一段可执行代码的引用,作为参数传递给其他代码。这允许较低级别的软件层调用在较高级别中定义的子例程(或函数)。”-维基百科
使用函数指针在C中回调
在C语言中,回调是使用函数指针实现的。函数指针-顾名思义,是指向函数的指针。
例如,int(*ptrFunc)();
在这里,ptrFunc是一个指向不带参数并返回整数的函数的指针。不要忘记插入括号,否则编译器将假定ptrFunc是一个普通的函数名,它不接受任何内容,并返回一个指向整数的指针。
下面是一些演示函数指针的代码。
#include<stdio.h>
int func(int, int);
int main(void)
{
int result1,result2;
/* declaring a pointer to a function which takes
two int arguments and returns an integer as result */
int (*ptrFunc)(int,int);
/* assigning ptrFunc to func's address */
ptrFunc=func;
/* calling func() through explicit dereference */
result1 = (*ptrFunc)(10,20);
/* calling func() through implicit dereference */
result2 = ptrFunc(10,20);
printf("result1 = %d result2 = %d\n",result1,result2);
return 0;
}
int func(int x, int y)
{
return x+y;
}
现在让我们尝试使用函数指针来理解C中回调的概念。
整个程序有三个文件:callback.c、reg_callback.h和reg_callback.c。
/* callback.c */
#include<stdio.h>
#include"reg_callback.h"
/* callback function definition goes here */
void my_callback(void)
{
printf("inside my_callback\n");
}
int main(void)
{
/* initialize function pointer to
my_callback */
callback ptr_my_callback=my_callback;
printf("This is a program demonstrating function callback\n");
/* register our callback function */
register_callback(ptr_my_callback);
printf("back inside main program\n");
return 0;
}
/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);
/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"
/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
printf("inside register_callback\n");
/* calling our callback function my_callback */
(*ptr_reg_callback)();
}
如果我们运行这个程序,输出将是
这是一个演示函数回调的程序内部寄存器回调my_callback内部回到主程序内部
上层函数作为正常调用调用下层函数,回调机制允许下层函数通过指向回调函数的指针调用上层函数。
Java中使用接口的回调
Java没有函数指针的概念它通过其接口机制实现回调机制在这里,我们声明了一个接口,该接口具有一个方法,当被调用方完成其任务时将调用该方法,而不是函数指针
让我通过一个示例演示一下:
回调接口
public interface Callback
{
public void notify(Result result);
}
呼叫者或更高级别的类
public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee
//Other functionality
//Call the Asynctask
ce.doAsynctask();
public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}
被调用者或下层函数
public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}
doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}
使用EventListener模式的回调
列表项目
此模式用于通知0到n个观察者/收听者特定任务已完成
列表项目
Callback机制和EventListener/Observer机制的区别在于,在回调中,被调用者通知单个调用者,而在Eventlisener/Oobserver中,被调用者可以通知对该事件感兴趣的任何人(通知可能会发送到应用程序中未触发任务的其他部分)
让我通过一个例子来解释一下。
事件界面
public interface Events {
public void clickEvent();
public void longClickEvent();
}
类小部件
package com.som_itsolutions.training.java.exampleeventlistener;
import java.util.ArrayList;
import java.util.Iterator;
public class Widget implements Events{
ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>();
ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();
@Override
public void clickEvent() {
// TODO Auto-generated method stub
Iterator<OnClickEventListener> it = mClickEventListener.iterator();
while(it.hasNext()){
OnClickEventListener li = it.next();
li.onClick(this);
}
}
@Override
public void longClickEvent() {
// TODO Auto-generated method stub
Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
while(it.hasNext()){
OnLongClickEventListener li = it.next();
li.onLongClick(this);
}
}
public interface OnClickEventListener
{
public void onClick (Widget source);
}
public interface OnLongClickEventListener
{
public void onLongClick (Widget source);
}
public void setOnClickEventListner(OnClickEventListener li){
mClickEventListener.add(li);
}
public void setOnLongClickEventListner(OnLongClickEventListener li){
mLongClickEventListener.add(li);
}
}
“类”按钮
public class Button extends Widget{
private String mButtonText;
public Button (){
}
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}
类复选框
public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}
活动类别
包com.som_itsolutions.training.java.exampleventlistener;
public class Activity implements Widget.OnClickEventListener
{
public Button mButton;
public CheckBox mCheckBox;
private static Activity mActivityHandler;
public static Activity getActivityHandle(){
return mActivityHandler;
}
public Activity ()
{
mActivityHandler = this;
mButton = new Button();
mButton.setOnClickEventListner(this);
mCheckBox = new CheckBox();
mCheckBox.setOnClickEventListner(this);
}
public void onClick (Widget source)
{
if(source == mButton){
mButton.setButtonText("Thank you for clicking me...");
System.out.println(((Button) mButton).getButtonText());
}
if(source == mCheckBox){
if(mCheckBox.isChecked()==false){
mCheckBox.setCheck(true);
System.out.println("The checkbox is checked...");
}
else{
mCheckBox.setCheck(false);
System.out.println("The checkbox is not checked...");
}
}
}
public void doSomeWork(Widget source){
source.clickEvent();
}
}
其他类别
public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}
主要类别
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}
从上面的代码中可以看到,我们有一个名为events的接口,它基本上列出了应用程序可能发生的所有事件。Widget类是所有UI组件(如Button、Checkbox)的基类。这些UI组件是实际从框架代码接收事件的对象。Widget类实现Events接口,并且它有两个嵌套接口,即OnClickEventListener和OnLongClickEventListen
这两个接口负责监听Widget派生的UI组件(如Button或Checkbox)上可能发生的事件。因此,如果我们将此示例与前面使用Java接口的回调示例进行比较,则这两个接口用作回调接口。因此,更高级别的代码(此处活动)实现了这两个接口。每当小部件发生事件时,将调用更高级别的代码(或在更高级别代码中实现的这些接口的方法,这里是Activity)。
现在让我讨论回调和Eventlistener模式之间的基本区别。正如我们提到的,使用Callback,被调用者只能通知单个调用者。但在EventListener模式的情况下,应用程序的任何其他部分或类都可以注册Button或Checkbox上可能发生的事件。此类类的示例是OtherClass。如果您看到OtherClass的代码,您会发现它已将自己注册为ClickEvent的侦听器,ClickEvent可能发生在“活动”中定义的Button中。有趣的是,除了Activity(调用者)之外,每当Button上发生单击事件时,也会通知这个OtherClass。
其他回答
这个问题的简单答案是回调函数是通过函数指针调用的函数。如果您将一个函数的指针(地址)作为参数传递给另一个函数,则当该指针用于调用它所指向的函数时,称为进行了回调
回调函数是在满足特定条件时应调用的函数。回调函数不是立即调用,而是在将来的某个时间点调用。
通常,当一个任务正在启动时,它将异步完成(即在调用函数返回后一段时间完成)。
例如,请求网页的函数可能要求其调用方提供回调函数,该回调函数将在网页完成下载时调用。
回调与回调函数
回调是在另一个函数完成执行后执行的函数 — 因此得名“回电”。
什么是回调函数?
将Funs(即函数对象)作为参数或返回Funs的函数称为高阶函数。任何作为参数传递的函数都称为回调函数。回调函数是作为参数传递给另一个函数(让我们调用这个其他函数otherFunction)的函数,回调函数在otherFunction内部调用(或执行)。
function action(x, y, callback) {
return callback(x, y);
}
function multiplication(x, y) {
return x * y;
}
function addition(x, y) {
return x + y;
}
alert(action(10, 10, multiplication)); // output: 100
alert(action(10, 10, addition)); // output: 20
在SOA中,回调允许插件模块从容器/环境访问服务。
来源
假设我们有一个函数sort(int*arraytobesorted,void(*algorithm selected)(void)),它可以接受一个函数指针作为其参数,可以在sort()实现的某个点使用。然后,这里选择的函数指针算法所处理的代码被称为回调函数。
我们可以选择任何算法,比如:
1. algorithmchosen = bubblesort
2. algorithmchosen = heapsort
3. algorithmchosen = mergesort ...
比如说,已经用原型实现了:
1. `void bubblesort(void)`
2. `void heapsort(void)`
3. `void mergesort(void)` ...
这是用于实现面向对象编程中的多态性的概念
我相信这种“回调”术语在很多地方被错误地使用了。我的定义大致如下:
回调函数是传递给某人并让他们在某个时间点称之为。
我认为人们只是读了维基定义的第一句话:
回调是对可执行代码的引用,或可执行代码,作为参数传递给其他代码。
我一直在使用很多API,看到了各种糟糕的例子。许多人倾向于将函数指针(对可执行代码的引用)或匿名函数(一段可执行代码)命名为“回调”,如果它们只是函数,为什么需要另一个名称?
实际上,wiki定义中只有第二句话揭示了回调函数和普通函数之间的区别:
这允许较低级别的软件层调用子程序(或函数)。
所以不同的是你将传递给谁,以及你传递的函数将如何被调用。如果您只是定义一个函数并将其传递给另一个函数,然后在该函数体中直接调用它,则不要调用回调。定义中说,传入的函数将由“较低级别”函数调用。
我希望人们能停止在模棱两可的语境中使用这个词,它不能帮助人们更好地理解,只能更糟。