回调函数

一、概念

对回调函数的概念一直不清晰,看过两次,时间一长就忘光了,因此在这篇文章中针对Java中的回调函数及其相关内容进行梳理总结。

记得以前刚接触回调函数是在异步IO中,操作系统将数据从内核空间复制到用户空间时会通过回调函数通知进程对数据进行处理,因此当时下意识的以为是线程间的一种通信机制;再后来顾名思义以为就是一个函数A调用函数B,执行B中的内容时会对A产生反馈,指导函数A的走向。

定义:回调函数被当成参数传递给中间函数,因此在传入一个回调函数之前,中间函数是不完整的,主函数在调用中间函数时,需要先执行回调函数,通过传入不同的回调函数,可以决定和改变中间函数的行为。

可见回调函数的调用是三个函数之间的关系,而不是想当然的两个函数。这三个函数分别是:主函数(调用函数)、中间函数和回调函数。下面的图片1-1,可以说明三个函数之间的关系。

图1-1三个函数的调用关系图

为了防止以后不清楚再多说几句,主函数A在调用中间函数B时,需要将回调函数C作为B参数传入,因此在B函数体中走到要执行的特定位置时就会调用C来进行处理,因此C不但能监视B执行的位置(运行状态),而且能干预B的运行。而C作为参数传入由B调用与由B直接调用的区别就是:前者只有A在调用B的时候才能确定C的内容,后者在程序编译或者写完时就已经确定C的内容了,前者因此更具灵活性。因此,回调函数其实就是多态的应用,能实现运行中的动态绑定。

二、实现

回调函数有同步和异步两种方式,现在我们将分别用Java语句来对其的调用过程进行实现。

2.1同步模式

首先回调函数我们最好设计为一个接口,这样便于扩展

public interface CallBack {

    //回调函数checkWork,学生完成作业后

    void checkWork();

}

然后设计中间函数

class Student{

    int a =1,b=2,c;

    Boolean flag;

    //中间函数doWork

    public void doWork(CallBack callback) {

        System.out.println("学生开始做作业。。。");

        c=4;//学生开始做计算题,并得出结果

        System.out.println("学生作业完成,通知老师检查");

        callback.checkWork();

        if(flag) {

            System.out.println("结果正确,学生回家。。");

        }else {

            System.out.println("结果不正确,继续修改。。");    

        }}}

最后由主函数进行调用

public class Test {    

    public static void main(String[] args){

        System.out.println("老师布置作业。。");

        Student student = new Student();

        student.doWork(new CallBack(){

            @Override

            public void checkWork() {

                if(student.c==3) {

                student.flag=true;                

                }else {

                student.flag=false;                

                }}});

        System.out.println("老师回家了。。。");

    }

}

调用过程如下:主函数调用中间函数即学生开始做作业计算a+b的值,完成之后通知老师即中间函数调用回调函数进行处理,将影响中间函数的走向,根据处理结果决定学生是否可以回家。

执行结果如下:

老师布置作业。。

学生开始做作业。。。

学生作业完成,通知老师检查

结果不正确,继续修改。。

老师回家了。。。

2.2异步模式

中间函数与回调函数保持不变,在主函数开一个线程进行函数的调用。

public class Test {    

    public static void main(String[] args){

        System.out.println("老师布置作业。。");

        //开启一个新的线程,将调用过程放入其中执行

        //主线程可以继续向下执行

        Runnable runnable = new Runnable() {    

            @Override

            public void run() {

                Student student = new Student();    

                student.doWork(new CallBack(){

                    @Override

                    public void checkWork() {

                        if(student.c==3) {

                        student.flag=true;                

                        }else {

                        student.flag=false;                

                        }}});            

                }};

        Thread t = new Thread(runnable);

        t.start();

        System.out.println("老师回家了。。。");

    }}

执行结果如下:

老师布置作业。。

老师回家了。。。

学生开始做作业。。。

学生作业完成,通知老师检查

结果不正确,继续修改。。

 总之,回调模式在生活中的例子非常常见,在编程中最常见的就是各种GUI编程里面的按钮点击什么的,通过回调可以将控制权转移,配合上异步模式,可以让系统设计的更加优雅。

参考文献:https://www.zhihu.com/question/19801131/answer/27459821

                            https://mp.weixin.qq.com/s/xn0Pa_Ilp0FjL_N_aswZtQ

原文地址:https://www.cnblogs.com/1995stone/p/13173186.html