转载请注意文章出处:https://blog.csdn.net/fengye454545/article/details/80198446
看了看网上的回调解释和例子,都那么的绕口,得看半天才能绕回来,其实吧,回调是个很简单的机制。在这里我用简单的语言先来解释一下:假设有两个类,分别是A和B,在A中有一个方法a(),B中有一个方法b();在A里面调用B中的方法b(),而方法b()中调用了方法a(),这样子就同时实现了b()和a()两个方法的功能。
疑惑:为啥这么麻烦,我直接在类A中的B.b()方法下调用a()方法就行了呗。
解答:回调更像是一个约定,就是如果我调用了b()方法,那么就必须要回调,而不需要显示调用
一、Java的回调-浅
我们用例子来解释:小明和小李相约一起去吃早饭,但是小李起的有点晚要先洗漱,等小李洗漱完成后,通知小明再一起去吃饭。小明就是类A,小李就是类B。一起去吃饭这个事件就是方法a(),小李去洗漱就是方法b()。
public class XiaoMing {
//小明和小李一起吃饭
public void eatFood() {
XiaoLi xl = new XiaoLi();
//A调用B的方法
xl.washFace();
}
public void eat() {
System.out.print("小明和小李一起去吃大龙虾");
}
}
那么怎么让小李洗漱完后在通知小明一起去吃饭呢
public class XiaoMing {
//小明和小李一起吃饭
public void eatFood() {
XiaoLi xl = new XiaoLi();
//A调用B的方法
xl.washFace();
eat();
}
public void eat() {
System.out.print("小明和小李一起去吃大龙虾");
}
}
不过上面已经说过了这个不是回调函数,所以不能这样子,正确的方式如下
public class XiaoLi{//小李
public void washFace() {
System.out.print("小李要洗漱");
XiaoMing xm = new XiaoMing();
//B调用A的方法
xm.eat();//洗漱完后,一起去吃饭
}
}
这样子就可以实现washFace()同时也能实现eat()。小李洗漱完后,再通知小明一起去吃饭,这就是回调。
二、Java的回调-中
可是细心的伙伴可能会发现,小李的代码完全写死了,这样子的场合可能适用和小明一起去吃饭,可是假如小李洗漱完不吃饭了,想和小王上网去,这样子就不适用了。其实上面是伪代码,仅仅是帮助大家理解的,真正情况下是需要利用接口来设置回调的。现在我们继续用小明和小李去吃饭的例子来讲讲接口是如何使用的。
小明和小李相约一起去吃早饭,但是小李起的有点晚要先洗漱,等小李洗漱完成后,通知小明再一起去吃饭。小明就是类A,小李就是类B。不同的是我们新建一个吃饭的接口EatRice,接口中有个抽象方法eat()。在小明中调用这个接口,并实现eat();小李声明这个接口对象,并且调用这个接口的抽象方法。这里可能有点绕口,不过没关系,看看例子就很清楚了。
EatRice接口:
public interface EatRice {
public void eat(String food);
}
小明
public class XiaoMing implements EatRice{//小明
//小明和小李一起吃饭
public void eatFood() {
XiaoLi xl = new XiaoLi();
//A调用B的方法
xl.washFace("大龙虾", this);//this指的是小明这个类实现的EatRice接口
}
@Override
public void eat(String food) {
// TODO Auto-generated method stub
System.out.println("小明和小李一起去吃" + food);
}
}
小李:
public class XiaoLi{//小李
public void washFace(String food,EatRice er) {
System.out.println("小李要洗漱");
//B调用了A的方法
er.eat(food);
}
}
测试Demo:
public class demo {
public static void main(String args[]) {
XiaoMing xm = new XiaoMing();
xm.eatFood();
}
}
测试结果:
小李要洗澡
小明和小李一起去吃大龙虾
这样子就通过接口的形式实现了软编码。通过接口的形式我可以实现小李洗漱完后,和小王一起去上网。代码如下
public class XiaoWang implements EatRice{//小王
//小王和小李一起去上网
public void eatFood() {
XiaoLi xl = new XiaoLi();
//A调用B的方法
xl.washFace("上网", this);
}
@Override
public void eat(String bar) {
// TODO Auto-generated method stub
System.out.println("小王和小李一起去" + bar);
}
}
测试结果:
小李要洗漱
小王和小李一起去上网
三、Java的回调-深
上面讲的都是同步回调,可是事实上,小李要洗漱后才能吃饭,在小李洗漱的时候,小明是要做自己的事情的,比如他在玩手机,这样子就是异步回调了。而且我们把代码正规化,比如在android点击事件中,你会发现你只要实现View.setOnclickListener(this),即可实现回调,那么像这样子的规范是如何实现的,在这一节里我将会提到。废话少说,先上代码。
EatRice接口没有变化,这里就省去接口代码展示
小明:
public class XiaoMing implements EatRice{
//小明和小李一起吃饭
public void eatFood() {
XiaoLi xl = new XiaoLi();
//A调用B的方法
xl.setEatRiceListener(this, "大龙虾");
}
@Override
public void eat(String food) {
// TODO Auto-generated method stub
System.out.print("小明和小李一起去吃" + food);
}
}
小李:
public class XiaoLi{//小李
protected EatRice er;
public void setEatRiceListener(EatRice er, String food) {
this.er = er;
washFace(food);
}
public void washFace(String food) {
System.out.print("小李要洗漱");
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
//小李洗漱的同时小明玩手机,开启线程实现异步
play();
Thread.sleep(10000);
System.out.print("10秒后 ");
//B调用A的方法
er.eat(food);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
//小明玩手机
public void play() {
System.out.println(" 小明要玩手机");
}
}
测试结果:
小李要洗漱 小明要玩手机
10秒后 小明和小李一起去吃大龙虾
首先先打印出 “小李要洗漱 小明要玩手机”,过了10秒后打印出“10秒后 小明和小李一起去吃大龙虾”。看到这里相信你对Java的回调有了新的认识吧。