又忙了一周,事情差不多解决了,终于有可以继续写我的博客了(各位看官久等了)。

  这次我们来谈一谈Java里的一个很有意思的东西——回调。

  什么叫回调,一本正经的来讲,在计算机程序设计中,回调函数是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。

  别急别急,且听我慢慢道来。

  举个栗子,设置这样一个情景,老板安排员工做事,然后让他做完后跟他电话说一声。老板当然不会在那里一直等员工做完事情才去做其他事,而是只交代完任务就去忙自己的事情了。

  这个例子包含了异步+回调的思想,员工做完任务后向老板报告这个过程,就叫回调,当然,报告的话,老板肯定先跟员工说好了报告方式,比如说邮件,电话等,而交代报告方式,就是注册回调函数,这里的回调函数必须符合接口的规范。

  好像还是有些不明白?来上代码吧。

  先定义一个接口:.

public interface ReceiveReport {
/**
* 接收报告
* @param name 员工名称
* @param report 报告内容
*/
public void receiveReport(String name,String report);
}

  定义一个Boss类实现这个接收报告的接口:

public class Boss implements ReceiveReport{
private Worker worker; public Boss(Worker worker){
this.worker = worker;
} /**
* 下达任务
*/
public void sendTask(){
worker.work(this);
} /**
* 接收报告
* @param name 员工名称
* @param report 报告内容
*/
public void receiveReport(String name,String report){
System.out.println("收到:"+name+" 的报告:"+report);
}
}

  定义一个Worker接口:

public interface Worker {
public void work(ReceiveReport boss);
}

  定义一个员工类。

public class Employee implements Worker{
private String name;//员工姓名 //构造器
public Employee(String name) {
this.name = name;
} /**
* 工作
* @param boss 任务名称
*/
public void work(ReceiveReport boss){
System.out.println(name + " is doing works.");
String report = "我已经完成了任务!";
boss.receiveReport(name,report);
}
}

  然后来测试一下:

public class Test {
public static void main(String[] args) {
Worker employee = new Employee("Frank");//定义一个员工
Boss boss = new Boss(employee);//定义一个Boss
//boss开始下达任务
boss.sendTask();
}
}

  测试结果:

Frank is doing works.
收到:Frank 的报告:我已经完成了任务!

  至此,员工与老板的交互就完成了,这就是一个简单的同步回调了。Boss通过Worker接口可以给员工安排工作,而不用去关心是哪个员工在工作,Worker通过ReceiveReport来向Boss报告工作情况,两个类通过接口进行回调交互,可以很好的解耦合,因为Boss可以安排不同的员工,只要他们实现了Worker接口就行,而员工也可以向不同的boss汇报情况,只要实现了ReceiveReport接口即可。

  其实回调的核心思想就是把自身的this指针传给调用方,就像这里把employee传入Boss类中,在work方法中又注册了回调,于是两者的交互性就很强了。

  那么为什么要用回调呢?如果Boss要在员工完成工作之前登记员工的一些信息,如姓名等,那么有了回调机制,通过把this指针传入,就能在Boss内部为所欲为了,而不需要通过设计新的方法来获取,而且需要获得的数据越多,回调的优势越明显。

  其实这里只是简单的一对一关系,如果是一个Boss,多个员工,那就是简单的观察者模式,如果是多个Boss多个员工,那就是简单生产者-消费者模式了。

  当然,这里仅仅是简单的同步回调。员工只能一个接一个的去完成任务,也就是说前一个员工必须等待后一个员工完成任务后才能开始任务,事实上,员工一般是同时进行工作的。

  如果换一个场景,现在有十个员工,老板发布任务,前三名完成的人有奖金奖励,那么就需要用到异步回调了,sendTask的时候使用线程即可,我们来修改一下代码:

/**
* @author Frank
* @create 2017/12/3
* @description 接收报告接口
*/
public interface ReceiveReport {
/**
* 接收报告
* @param worker 员工
* @param report 报告内容
*/
public void receiveReport(Worker worker,String report);
}
/**
* @author Frank
* @create 2017/12/3
* @description 工人接口
*/
public interface Worker {
public void work(String taskName);
public void setReceiveReport(ReceiveReport boss);
public void getReward(Double money);
public String getName();
}
import java.util.Random;

/**
* @author Frank
* @create 2017/12/3
* @description 员工类
*/
public class Employee implements Worker{
private ReceiveReport boss;
private String name;//员工姓名 @Override
public String getName() {
return name;
} //构造器
public Employee(String name) {
this.name = name;
} public void setReceiveReport(ReceiveReport boss) {
this.boss = boss;
} @Override
public void getReward(Double money) {
System.out.println(name+"由于表现突出,获得$"+money+"现金奖励!");
} /**
* 工作
* @param taskName 任务名称
*/
public void work(String taskName){
System.out.println(name + " is doing works:"+taskName);
Random random = new Random();
Integer time = random.nextInt(10000);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
String report = "顺利完成任务!";
//通知老板
boss.receiveReport(this,report);
}
}
import java.util.ArrayList;
import java.util.List; /**
* @author Frank
* @create 2017/12/3
* @description Boss类
*/
public class Boss implements ReceiveReport{
private List<Worker> workers = new ArrayList<>();//老板管理的员工
private volatile int index;//顺序 /**
* 添加员工
* @param worker 员工
*/
public void addWorker(Worker worker){
workers.add(worker);
worker.setReceiveReport(this);
} /**
* 下达任务
*/
public void sendTask(String task){
//给各个员工依次下达任务
for (Worker w:workers){
new Thread(new Runnable() {
@Override
public void run() {
w.work(task);
}
}).start();
}
} /**
* 接收报告
* @param worker 员工
* @param report 报告内容
*/
public void receiveReport(Worker worker,String report){
int index = ++this.index;
System.out.println(worker.getName()+"获得第"+index+"名");
if (index <= 3){
//给前三名发奖金
worker.getReward(1000.0*(4-index));
}
}
}
/**
* @author Frank
* @create 2017/12/3
* @description
*/
public class Test {
public static void main(String[] args) {
Boss boss = new Boss();//定义一个Boss
//定义十个员工
for (int i=0;i<10;i++){
Worker worker = new Employee("Employee["+i+"]");
boss.addWorker(worker);
}
//boss开始下达任务
boss.sendTask("Say Hello"); }
}

  这里没有使用锁,因为设置的时间间隔区间为0-10s,发生并发冲突的概率很低,而且由于现在还没有说多线程的内容,所以暂时先不使用。只需要知道在sendTask方法中,依次启动了线程来调用每个Worker的work方法,线程启动后会同时执行,执行完毕后,又会调用Boss的receiveReport方法来向Boss反馈结果,接收结果后,根据完成顺序,再调用Worker的getReward方法来给前三名发奖金。其实这里是双向回调了,Boss把this指针传给了Worker,Worker又把自己的this指针传给了Worker。

  程序执行结果如下:

Employee[0] is doing works:Say Hello
Employee[4] is doing works:Say Hello
Employee[3] is doing works:Say Hello
Employee[2] is doing works:Say Hello
Employee[1] is doing works:Say Hello
Employee[5] is doing works:Say Hello
Employee[7] is doing works:Say Hello
Employee[6] is doing works:Say Hello
Employee[9] is doing works:Say Hello
Employee[8] is doing works:Say Hello
Employee[9]获得第1名
Employee[9]由于表现突出,获得$3000.0现金奖励!
Employee[7]获得第2名
Employee[7]由于表现突出,获得$2000.0现金奖励!
Employee[3]获得第3名
Employee[3]由于表现突出,获得$1000.0现金奖励!
Employee[1]获得第4名
Employee[0]获得第5名
Employee[5]获得第6名
Employee[4]获得第7名
Employee[8]获得第8名
Employee[6]获得第9名
Employee[2]获得第10名

  因为使用了多线程,所以每次运行的结果可能都会不一样,如果得到了不一样的结果,那是很正常的现象。

  举了这两个栗子,对回调应该也有了一定的了解了吧。

  其实回调只是一种思想,并不是java中独有的内容,思想这种东西,是为了解决特定场景下的特定问题而出现的,只有被正确应用了才有它的价值,而不要为了使用它而使用它。

  至此,回调讲解完毕,如有说明有误的地方,欢迎各位批评指正。也欢迎大家继续关注。

  

Java中的回调的更多相关文章

  1. Java中的回调函数学习

    Java中的回调函数学习 博客分类: J2SE JavaJ#  一般来说分为以下几步: 声明回调函数的统一接口interface A,包含方法callback(); 在调用类caller内将该接口设置 ...

  2. Java中的回调函数学习-深入浅出

    Java中的回调函数一般来说分为下面几步: 声明回调函数的统一接口interface A.包括方法callback(); 在调用类caller内将该接口设置为私有成员private A XXX; 在c ...

  3. 【Java入门提高篇】Day4 Java中的回调

    又忙了一周,事情差不多解决了,终于有可以继续写我的博客了(各位看官久等了). 这次我们来谈一谈Java里的一个很有意思的东西——回调. 什么叫回调,一本正经的来讲,在计算机程序设计中,回调函数是指通过 ...

  4. 夯实Java基础系列11:深入理解Java中的回调机制

    目录 模块间的调用 多线程中的"回调" Java回调机制实战 实例一 : 同步调用 实例二:由浅入深 实例三:Tom做题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 ...

  5. 【Java入门提高篇】Day5 Java中的回调(二)

    Java中有很多个Timer,常用的有两个Timer类,一个java.util包下的Timer,一个是javax.swing包下的Timer,两个Timer类都有用到回调机制.可以使用它在到达指定时间 ...

  6. Java中的回调函数

    本例拿apache commons dbutils举例 回调函数: 回调是指在执行时,具体的封装处理工用由第三方的类来实现. 回调一般由两部分组成 1:调用类 - QueryRunner.实例类 2: ...

  7. Android中自定义veiw使用Java中的回调方法

    //------------------MainActivity----中---------------------------------- import android.os.Bundle;imp ...

  8. 关于JAVA中的回调接口传值机制

    详见博文http://blog.csdn.net/xiaanming/article/details/8703708

  9. java与安卓中的回调callback学习笔记

    1.回调的简单设计如下: package com.listercai.top; public class A { private CallBack callBack; private AnotherC ...

随机推荐

  1. Git相关操作四

    1.克隆远程仓库 git clone remote_location clone_name remote_location为仓库地址,clone_name为要克隆到本地的仓库名称. 2.显示对应克隆地 ...

  2. js页面间通信方法(storage事件)(浏览器页面间通信方法)

    在写页面的时候有时会遇到这样的需求,需要两个页面之间传递数据或者一个事件.这个时候,就需要用到我今天所要讲的storage事件,学习这个事件之前,需要先了解localStorage的用法.具体用法可以 ...

  3. Visual Studio插件Resharper 2016.1 及以上版本激活方法【亲测有效】

    1.破解补丁下载:https://flydoos.ctfile.com/fs/y80153828783.下载下来解压之后的文件如下: 2.打开文件夹“IntelliJIDEALicenseServer ...

  4. Kinect v2(Microsoft Kinect for Windows v2 )配置移动电源解决方案

    Kinect v2配置移动电源解决方案 Kinect v2如果用于移动机器人上(也可以是其他应用场景),为方便有效地展开后续工作,为其配置移动电源是十分必要的. 一.选择移动电源 Kinect v2原 ...

  5. asp中日志方法

    代码文件log.asp中内容如下: <% Function getPath() getPath = request.servervariables("APPL_PHYSICAL_PAT ...

  6. LeetCode 245. Shortest Word Distance III (最短单词距离之三) $

    This is a follow up of Shortest Word Distance. The only difference is now word1 could be the same as ...

  7. IntelliJ IDEA创建多模块依赖项目

    刚从Eclipse转IDEA, 所以记录一下IDEA的使用 创建多模块依赖项目 1. 新建父工程 这样就创建好了一个普通项目,一般我们会把src删掉,在此项目下新建新的模块 2. 新建子模块 创建供前 ...

  8. 读书笔记-你不知道的JS中-promise(3)

    坑坑坑 关于术语:决议.完成以及拒绝. 首先观察Promise(..)构造器: var p = new Promise(function(x, y) { //x() 用于完成 //y() 用于拒绝 } ...

  9. Leetcode题解(23)

    69. Sqrt(x) 题目 分析,题目实现求一个int数的平方根,最暴力的算法就是逐个遍历,从1开始到x,判断是否有一个数i,其中满足i*i<=x,并且(i+1)*(i+1)>x;这个算 ...

  10. Sqoop的安装部署

    在root的用户下 1):前提 安装JDK环境 2):前提 安装Hadoop和Hive客户端环境,如果需要导出到HBase则需要安装HBase客户端 3):下载sqoop : 命令: wget htt ...