1.什么是回调

实际项目中,服务端的同学经常会提到回调这个词。那么回调到底是什么呢?
所谓回调,就是客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数。例如Win32下的窗口过程函数就是一个典型的回调函数。
一般说来,C不会自己调用B,C提供B的目的就是让S来调用它,而且是C不得不提供。由于S并不知道C提供的B叫甚名谁,所以S会约定B的接口规范(函数原型),然后由C提前通过S的一个函数R告诉S自己将要使用B函数,这个过程称为回调函数的注册,R称为注册函数。
下面举个通俗的例子:
某天,我打电话向你请教问题,当然是个难题,😃,你一时想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。
这个例子说明了“异步+回调”的编程模式。其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范。

2.老板-下属例子

有这么一个实际例子:有个老板手下有很多下属,每个下属都分配一些工作。于是老板跟下属约定:当下属做完手头工作以后,通知他已经做完了工作。下面来模拟一下。
首先我们定义老板的回调接口:

public interface CallBack {

    void execute();
}

然后创建回调对象,即老板本人:

public class Boss implements CallBack {

    @Override
    public void execute() {
        System.out.println("get the msg in : " + System.currentTimeMillis());
    }

}

接下来创建下属类,下属必须知道老板的回调地址,或者说必须持有老板对象的引用,这样他才能通知回老板:

public class Subordinate {

    private CallBack callBack;

	//得到老板的联系方式,也就是注册  
    public Subordinate(CallBack callBack) {
        this.callBack = callBack;
    }

    public void beginThread() {
        for(int i=0; i<10000; i++) {
        }
        callBack.execute();
    }
}

下面来测试一下:

public class Client {

    public static void main(String[] args) {
        Boss boss = new Boss();
        // 将回调的对象(老板)传进来
        Subordinate subordinate = new Subordinate(boss) ;
        subordinate.beginThread();
    }
}

代码运行结果:

get the msg in : 1529757722172

##3.用回调的方式计算程序运行时间

回调接口

public interface CallBack {

    void execute();
}

实现回调接口

public class Windows implements CallBack{

    private Tools tools;

    public Windows(Tools tools) {
        this.tools = tools;
    }

    @Override
    public void execute() {
        tools.runStart();
        List<Integer> list = new ArrayList<>();
        for(int i=0; i<1000000; i++) {
            list.add(i);
        }
        tools.runStop();
    }
}

控制器,计算程序运行时间工具类:

public class Tools {

    public void runStart() {
        System.out.println("the running start!");
    }

    public void getRunTime(CallBack callBack) {
        long begin = System.currentTimeMillis();
        callBack.execute();
        long end = System.currentTimeMillis();
        System.out.println("[use time]:"  + (end - begin));
    }

    public void runStop() {
        System.out.println("the running stop!");
    }
}

测试代码:

public class Test {

    public static void main(String[] args) {
        Tools tools = new Tools();
        Windows windows = new Windows(tools);
        tools.getRunTime(windows);
    }
}