转载请注意文章出处:https://blog.csdn.net/fengye454545/article/details/80198446
有一段时间没写博客了,可能是因为懒了吧。前几天公司面试有问道java回调的问题,因为这方面也没有太多研究,所以回答的含糊不清,这回特意来补习一下。看了看网上的回调解释和例子,都那么的绕口,得看半天才能绕回来,其实吧,回调是个很简单的机制。在这里我用简单的语言先来解释一下:假设有两个类,分别是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秒后 小明和小李一起去吃大龙虾”。看到这里相信你对Java的回调有了新的认识吧。
菜鸟一只,如有不对之处请指出。您的鼓励是我写作的最大动力!