回调函数在C语言、JS、Java中的实现

回调函数:回调函数就是一个被作为参数传递的函数。

在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。

回调函数的使用可以大大提升编程的效率,这使得它在现代编程中被非常多地使用。同时,有一些需求必须要使用回调函数来实现。

机制

  ⑴定义一个回调函数;

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

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

意义

       因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

        回调函数在实际中有许多作用。假设有这样一种情况:我们要编写一个库,它提供了某些排序算法的实现(如冒泡排序快速排序shell排序、shake排序等等),为了能让库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,能让库可用于多种数据类型(int、float、string),此时,可以使用函数指针,并进行回调。

        回调可用于通知机制。例如,有时要在A程序中设置一个计时器,每到一定时间,A程序会得到相应的通知,但通知机制的实现者对A程序一无所知。那么,就需一个具有特定原型的函数指针进行回调,通知A程序事件已经发生。实际上,API使用一个回调函数SetTimer来通知A程序。如果没有提供回调函数,它还会把一个消息发往程序的消息队列

        另一个使用回调机制的API函数是EnumWindow,它枚举屏幕上所有的顶层窗口,每个窗口都可以通过它调用另一个程序提供的函数,并传递窗口的处理程序。例如:如果被调用者返回一个值,就继续进行迭代;否则,退出。EnumWindow并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为基于返回值,它将继续执行或退出。

C语言的回调函数只能通过函数指针实现,在C++中则可以使用匿名函数(lambda)或仿函数(functor)作为回调函数。

摘要百度百科.......

C语言回调函数实例

函数指针,指向一个函数的地址。把它作为形参,通过call来调用。对于上面含义的理解(如理解有错误,欢迎指正。)

回调函数(call(show)/call(hello))可以把调用者与被调用者分开(我们不需要在call()中写hello();show();方法来调用他们),所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

①不带参数的回调函数

void call(void (*fp)()){
    fp();//回调函数
}
void hello(){
    printf("hello world!");
}
void show(){
    printf("show ");
}
int main(int argc, char *argv[]){
    call(hello);
    call(show);
}

②带参数的回调函数     (在c++语言中,我们可以利用方法的重载,使其功能更为强大。)

#include <stdio.h>

int compute_func(int (*func_ptr)(int,int),int x,int y){
	return func_ptr(x,y);
}
int sum(int x,int y){
	return x+y;
}
int sub(int x,int y){
	return x-y;
}
int product(int x,int y){
	return x*y;
}

int main()
{
   int a=10;
   int b=5;		
   printf("%d\n",a,b,compute_func(sum,a,b));
   return 0;
}

JS回调函数实例

https://www.bilibili.com/video/BV1W7411M76j/?spm_id_from=333.788.recommend_more_video.0

感觉这老外将的贼好。

①下面的回调函数实例其实和C语言中利用函数指针实例类似。另外在模拟一个场景,利用参数为一个匿名函数,实现其它的功能。

<script>
  let calc = function(num1,num2,callback){
    if(typeof callback === 'function'){
      return callback(num1,num2);
    }
  }
  let add =  function(a,b){
    return a+b;
  }
  let doOthersOper = function(a,b){
    console.log(`a= ${a} b= ${b}`)
  }
  let sub = function(a,b){
    return a-b;
  }
  console.log(calc(10,5,sub))
  console.log(calc(10,5,doOthersOper))
  //传递一个匿名的函数 ,来实现a*b 实际上我们可以另外在写一个mutil功能,
  //但是这个函数我们只是用它一次,我们这时就可以传递一个匿名函数,
  //因此在在调用calc函数时,要判断传入的参数类型是一个function,要不然会报错
  console.log(calc(10,5,function(a,b){
    return a*b
    })
  )

②SetTimeout 函数.利用它模拟一个作业的情形。

 let doHomeWork = function(subject,callback){
    setTimeout(function(){
      console.log(`starting my ${subject} homeWork`)
      callback()
    },5000)
  }
  doHomeWork('math',function(){
    console.log('Finished my homeWork')
  })

③ 利用 sort 函数理解上面的话

        回调函数在实际中有许多作用。假设有这样一种情况:我们要编写一个库,它提供了某些排序算法的实现(如冒泡排序快速排序shell排序、shake排序等等),为了能让库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,能让库可用于多种数据类型(int、float、string),此时,可以使用函数指针,并进行回调。

var arr = [
    {name:'zopp',age:0},
    {name:'gpp',age:18},
    {name:'yjj',age:8}
];
//匿名函数来实现比较器,它是一个回调函数
console.log(arr.sort(function(val1,val2){
          return val1.age - val2.age;
        }))

//下面是基于Array.prototype.sort的某种实现   匿名函数==>comparefn
function InnerArraySort(array, length, comparefn) {
  .......
}

 

④:Ajax中的回调函数 success   (异步回调)

先引入回调过程:函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b。那么这个过程就叫回调。

由这篇文章引出的问题:https://www.cnblogs.com/sharpxiajun/archive/2012/04/26/2471990.html  

其实这篇文章所述的是,怎样将回调函数获取的数据存储到全局变量中使用而出现额一些问题。js是从上往下执行的,Ajax请求是异步的,当所有的语句执行完后,异步获取的数据还没获取完,因此取不到数据。

解决方法:https://www.cnblogs.com/dand/p/10534571.html

Java回调方法实例

回调函数的利用场景:由易到难

 https://www.cnblogs.com/yangmin86/p/7090882.html  

 https://www.cnblogs.com/shenwen/p/9046482.html

 https://zhuanlan.zhihu.com/p/30052334

概念:Java中没有函数指针的概念,Java实现回调方法利用的是接口。在接口中定义回调函数(参数类型为一个引用类型)利用它来模拟函数指针

A类调用B类的中的方法  B类中的方法完之后主动调用A类的callback方法

场景一:我认为这个例子是最后理解回调机制的

            说明:老板让员工打印文件,员工打印完后通知老板(调用老板的方法通知老板)。

public class Emp {
    public void doPrint(){
        System.out.println("帮老板打印文件!");
        Boss boss = new Boss();
        boss.callBack();
    }
}

public class Boss {
    public static void main(String[] args) {
        Emp emp = new Emp();
        emp.doPrint();
    }
    public void callBack(){
        System.out.println("老板打印好了,请你签收!");
    }
}

场景二:利用接口来模拟 

/* CallBack  : A类   TestCallBack:B类*/
public class TestCallBack {
    public interface CallBack{
        String getString();
        int getNumber();
    }
    private CallBack callBack;

    //①:A类调用B类中的方法,要在B类传入自己的引用
    public TestCallBack(CallBack callBack){
        this.callBack = callBack;
    }
    //②:用A类中的引用调用自身的方法 
    public void run(String string){
        System.out.println(callBack.getString());
    }
    public void run(int number){
        System.out.println(callBack.getNumber());
    }
}
/*测试CallBack接口中的回调函数*/
public class Main {
    public static void main(String[] args) {
        //我们在外创建一个A类的对象,执行完某些操作后又在执行A类自己的 run()方法
        //而这些特定的操作,我们可以根据接口自己定义,然后实现,只需给定特殊的参数来调用它们。
        //从而避免直接调用,解耦。对于有些操作,我们指向调用一次,我们可以采用匿名实现类的方法
        TestCallBack testCallBack = new TestCallBack(new TestCallBack.CallBack() {
            @Override
            public String getString() {
                return "你是人间的四月天";
            }

            @Override
            public int getNumber() {
                return 10086;
            }
        });
        testCallBack.run(1);
    }
}

在实际的开发中,回调方法可以运用的非常灵活。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值