java回调函数机制

来源:互联网 发布:中国知网数据库 编辑:程序博客网 时间:2024/05/29 09:35

Java回调函数机制


参考了网上的一些资料,下面也做出一些总结,供初学者了解学习。


一、 概述

软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调、异步调用 

同步调用:一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用; 

回调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口; 

异步调用:一种类似消息或事件的机制,解决了同步阻塞的问题,它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。




回调和异步调用的关系非常紧密:使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。


理解异步和同步

1.通俗说,异步就是不需要等当前执行的动作完成,就可以继续执行后面的动作。

2.通常一个程序执行的顺序是:从上到下,依次执行。后面的动作必须等前面动作执行完成以后方可执行。这就是和异步相对的一个概念——同步。


案例:

A、张三打电话给李四,让李四帮忙写份材料。

B、李四接到电话的时候,手上有自己的工作要处理,但他答应张三,忙完手上的工作后马上帮张三写好材料,并传真给张三。

C、通完电话后,张三外出办事。


说明:

张三给李四通完电话后,就出去办事了,他并不需要等李四把材料写好才外出。那么张三让李四写材料的消息就属于异步消息。

相反,如果张三必须等李四把材料写好才能外出办事的话,那么这个消息就属于同步消息了。


二、 异步的实现

传统的程序执行代码都是从上到下,一条一条执行。但生活中有很多情况并不是这样,以上的案例中,如果李四需要几个小时以后才能帮张三写好材料的话,那张三就必须等几个小时,这样张三可能会崩溃或者抓狂。这种一条龙似的处理,显示不太合理。


可以使用以下办法来处理这种问题:

张三找王五去给李四打电话,等李四写好材料后,由王五转交给张三。这样张三就可以外出办其他的事情了。

 

问题得到了合理的解决,之前张三一条线的工作,由张三和王五两条线来完成了,两边同时进行,彼此不耽误。

 

三、 计算机语言的实现

办法有了,如何用程序来模拟实现呢?

 

A、以前由一个线程来处理的工作,可以通过新增一个线程来达到异步的目的。

B、最后李四写好的材料必须交给张三,以做他用。这就是回调。

 

回调你可以这样来理解:

A发送消息给B,

B处理好A要求的事情后,将结果返回给A,

A再对B返回的结果来做进一步的处理。

 

四、 模拟异步消息的发送与回调

A、 回调的实现

/**  * 回调接口  */  public interface CallBack {      /**      * 执行回调方法      * @param objects   将处理后的结果作为参数返回给回调方法      */      public void execute(Object... objects );  }  

Java是面向对象的语言,因此回调函数就变成了回调接口。


B、 消息的发送者

/**  * 简单本地发送异步消息的类  */  public class Local implements CallBack,Runnable{            /**      * 远程接收消息的类,模拟point-to-point      */      private Remote remote;            /**      * 发送出去的消息      */      private String message;            public Local(Remote remote, String message) {          super();          this.remote = remote;          this.message = message;      }        /**      * 发送消息      */      public void sendMessage()      {          /**当前线程的名称**/          System.out.println(Thread.currentThread().getName());          /**创建一个新的线程发送消息**/          Thread thread = new Thread(this);          thread.start();          /**当前线程继续执行**/          System.out.println("Message has been sent by Local~!");      }        /**      * 发送消息后的回调函数      */      public void execute(Object... objects ) {          /**打印返回的消息**/          System.out.println(objects[0]);          /**打印发送消息的线程名称**/          System.out.println(Thread.currentThread().getName());          /**中断发送消息的线程**/          Thread.interrupted();      }            public static void main(String[] args)      {          Local local = new Local(new Remote(),"Hello");                    local.sendMessage();      }        public void run() {          remote.executeMessage(message, this);                }  }  

C、 远程消息的接收者

/**  * 处理消息的远程类  *  */  public class Remote {        /**      * 处理消息      * @param msg   接收的消息      * @param callBack  回调函数处理类      */      public void executeMessage(String msg,CallBack callBack)      {          /**模拟远程类正在处理其他事情,可能需要花费许多时间**/          for(int i=0;i<1000000000;i++)          {                        }          /**处理完其他事情,现在来处理消息**/          System.out.println(msg);          System.out.println("I hava executed the message by Local");          /**执行回调**/          callBack.execute(new String[]{"Nice to meet you~!"});      }        }  

执行 Local 类的 main 方法。
 
注意Local类中:

remote.executeMessage(message, this);

executeMessage 方法需要接收一个message参数,表示发送出去的消息,而CallBack参数是他自己,也就是这里的this。表示发送消息后,由Local类自己来处理,调用自身的execute方法来处理消息结果。

如果这里不是用this,而是用其他的CallBack接口的实现类的话,那就不能称之为“回调”了,在OO的世界里,那就属于“委派”。也就是说,“回调” 必须是消息的发送者来处理消息结果,否则不能称之为回调。这个概念必须明确。



五、更多异步 + 回调 编程模式的例子


1.某天,我打电话向你请教问题,当然是个难题,你一时想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想
出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范


2.有一位老板很忙,他没有时间盯着员工干活,然后他告诉自己的雇员,干完当前这些事情后,告诉他干活的结果。

创建一个回调接口,让老板得告知干完活如何找到他的方式:留下老板办公室地址:

package net.easyway.test;    /**  * 此接口为联系的方式,不论是电话号码还是联系地址,作为  * 老板都必须要实现此接口 *  */  public interface CallBackInterface {        public void execute();  }

创建回调对象,就是老板本人,因为员工干完活后要给他打电话,因此老板必须实现回调接口,不然员工去哪里找老板?



package net.easyway.test;    /**  * 老板是作为上层应用身份出现的,下层应用(员工)是不知道  * 有哪些方法,因此他想被下层应用(员工)调用必须实现此接口  *  */  public class Boss implements CallBackInterface {            @Override      public void execute() {          System.out.println("收到了!!" + System.currentTimeMillis());                }  }

创建控制类,也就是员工对象,他必须持有老板的地址(回调接口),即使老板换了一茬又一茬,办公室不变,总能找到对应的老板。



package net.easyway.test;    /**  * 员工类,必须要记住,这是一个底层类,底层是不了解上层服务的  *  */  public class Employee {        private CallBackInterface callBack = null;            //告诉老板的联系方式,也就是注册      public void setCallBack(CallBackInterface callBack){          this.callBack = callBack;      }            //工人干活      public void doSome(){          //1.开始干活了          for(int i=0;i<10;i++){              System.out.println("第【" + i + "】事情干完了!");          }                    //2.告诉老板干完了          callBack.execute();      }  }


测试类:

package net.easyway.test;    public class Client {        public static void main(String[] args) {                              Employee emp = new Employee();                    //将回调对象(上层对象)传入,注册          emp.setCallBack(new Boss());                    //开启控制器对象运行          emp.doSome();      }    }


8 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信界面变小了怎么办 拉杆箱螺丝掉了怎么办 洗衣机应急门锁没有拉绳怎么办? 奔驰glc发动机声音大怎么办 淋膜机模具螺丝拧不动怎么办 一字螺丝滑丝了怎么办 螺丝拧歪卡住了怎么办 车牌螺丝拧歪了怎么办 空心墙打膨胀螺丝打不上怎么办 沉孔内六角螺丝滑丝怎么办 内六角螺丝滑了怎么办? 三色灯不变光了怎么办 卧室灯不变色了怎么办 圆柱齿轮减速机噪音大怎么办 轴与套间隙生锈怎么办 汽车停小区被刮怎么办 下楼梯摔跤了 屁股疼 怎么办 剧烈咳嗽震的肚子疼怎么办 饺子粘在盘子上怎么办 生饺子粘在盘子怎么办 饺子粘在案板上怎么办 饺子冷冻粘起了怎么办 冰箱饺子冻住了怎么办 水饺都冻一块了怎么办 wps卸载了后文件打不开怎么办 六角螺母拧滑了怎么办 梅花内六角螺丝扭滑丝了怎么办 眼镜螺丝滑丝了怎么办 大螺丝拆不下来怎么办 一字螺丝扭不动怎么办 带帽的螺丝拧花怎么办 螺丝拧不出来了怎么办 小六角螺丝滑丝怎么办 螺丝拧不下来了怎么办 固定水龙头的螺母扭不动怎么办 小螺丝帽拧花了怎么办 6角螺丝帽拧圆了怎么办 眼镜螺丝滑扣了怎么办 眼镜的螺丝掉了怎么办 螺丝松了怎么办小窍门 螺丝松了怎么办 小窍门