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的回調有了新的認識吧。


菜鳥一隻,如有不對之處請指出。您的鼓勵是我寫作的最大動力!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章