在说回调之前,说一下3种调用方式:
1.同步调用
栗子:比如我们去商店买东西,到了商店,我们选择好商品,等待售货员找到你要的商品,并拿给你。这个时候,如果售货员着商品需要5秒,那你就等待5秒,如果需要1分钟,你就得等待1分钟。这就是同步调用,被调用的方法如果需要执行很长时间,那么你的主线程就会阻塞在这里,大大降低了效率和体验。
2.异步调用
栗子:这里的箭头是单向的,也就是说我告诉售货员我需要什么商品,你找你的,我走我的,互不影响。这里就涉及一个问题,就是返回结果的处理。我们可以使用Callable。(Runnable不会返回线程结果,Callable可以返回线程运算结果)。举一个场景,比如我们在登陆或注册的时候,点击发送验证码,这个时候我们的页面肯定不能阻塞在那里等在验证码发送完在响应,所以就用到了异步处理。把需要发送验证码的一些信息扔到消息队列里面,邮件或短信相关的服务器收到消息后去执行即可。
3.回调
栗子:比如当前没有货,你留下了你的联系方式,等待到货的时候,售货员联系你,这个时候你就可以取走你的商品。留下联系方式就是注册回调函数,到货是触发回调关联时间,售货员联系你是调用回掉函数,你去取回商品是响应回调函数。
用到回调的地方有很多,比如我们添加一个按钮,启一个线程来进行监听并且绑定一个回调函数,当按钮被点击的时候,就会去调用你绑定的回调函数。
上代码
场景:
我们去天猫买东西,等待商品邮寄过来的时间内,我们可以干任何事情。当商品到达的时候,联系我即可。
新建一个回调函数接口ICallBack.java
public interface ICallBack {
void callBackExecute(String msg);
}
新建一个天猫类,模拟商品邮寄的过程TmallShop.java
public class TmallShop {
public void postGoods(ICallBack callBack) {
for (int i = 0; i < 5; i++) {
System.out.println("Posting " + (i + 1) + " day");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String msg = "Goods Arrived";
callBack.callBackExecute(msg);
}
}
新建一个顾客类,模拟购物、等待、响应过程Customer.java
public class Customer {
private static boolean Waiting = false;
private static Integer times = 0;
public static void main(String[] args) {
TmallShop shop = new TmallShop();
new Thread(() -> shop.postGoods(msg -> {
Waiting = false;
System.out.println(msg);
System.out.println("I've won " + times + " times");
})).start();
Waiting = true;
while (Waiting) {
System.out.println("Playing LOL ... victory !");
times++;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
以上就是我对回调的理解和一个简单的小栗子
写法不固定,根据实际情况转变
它并不是一个语言独有的特性,而是一种写法,一种解决问题的方案