Java的回调-由浅入深(保证简单易懂)

转载请注意文章出处: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的回调有了新的认识吧。


菜鸟一只,如有不对之处请指出。您的鼓励是我写作的最大动力!

猜你喜欢

转载自blog.csdn.net/fengye454545/article/details/80198446