首頁 >Java >java教程 >妙解Java中的回呼機制(CallBack)

妙解Java中的回呼機制(CallBack)

高洛峰
高洛峰原創
2017-01-24 13:25:261424瀏覽

前言

最近學習java,接觸到了回呼機制(CallBack)。初識時感覺比較混亂,而且在網路上搜尋到的相關的講解,要嘛一言帶過,要嘛說的比較單純的像是給CallBack做了一個定義。當然了,我在理解了回調之後,再去看網路上的各種講解,確實沒什麼問題。但是,對於初學的我來說,缺了一個循序漸進的過程。

回調是一種雙向調用模式,什麼意思呢,就是說,被調用方在被調用時也會調用對方,這就叫回調。 「If you call me, i will call back」。 

不懂?沒關係,先看看這個可以說比較經典的使用回調的方式: 

class A實現介面InA ——背景1

class A中包含一個class B的引用b ——背景2

class B中包含一個class B的引用b ——背景2

class B中包含一個class B的引用b ——背景2

class B有一個參數為InA的方法test(InA a) ——背景3

A的對象a調用B的方法傳入自己,test(a) ——這一步驟相當於you call me


然後b就可以在test方法中呼叫InA的方法-這一步相當於i call you back

開始之前,先想像一個場景:幼稚園的小朋友剛剛學習了10以內的加法。

下面,將我對回調機制的個人理解,按照由淺到深的順序描述一下,如有不妥之處,望不吝賜教!

第1章. 故事的緣起

幼師在黑板上寫一個式子 “1 + 1 = ”,由小明同學來填空。

由於已經學習了10以內的加法,小明同學可以完全靠自己來計算這個題目,模擬該過程的代碼如下:

public class Student
 {
  private String name = null;
 
  public Student(String name)
  {
   // TODO Auto-generated constructor stub
   this.name = name;
  }
 
  public void setName(String name)
  {
   this.name = name;
  }
 
  private int calcADD(int a, int b)
  {
   return a + b;
  }
 
  public void fillBlank(int a, int b)
  {
   int result = calcADD(a, b);
   System.out.println(name + "心算:" + a + " + " + b + " = " + result);
  }
 }

小明同學在填空(fillBalnk)的時候,直接心算(clacADD)了一下,得出結果是2,並將結果寫在空格里。測試程式碼如下:

public class Test
 {
  public static void main(String[] args)
  {
  int a = 1;
   int b = 1;
   Student s = new Student("小明");
   s.fillBlank(a, b);
  }
 }

   


運作結果如下:

小明心算:1 + 1 = 2

該過程完全由Student類別的實例檔案

第2章. 幼師的找茬

課間,幼師突發奇想在黑板上寫了「168 + 291 = 」讓小明完成,然後回辦公室了。

花擦!為什麼所有老師都跟小明過不去啊?明明超綱了好不好!這時候小明同學明顯不能再像上面那樣靠心算來完成了,正在懵逼的時候,班上的小紅同學遞過來一個只能計算加法的計算器(奸商啊)! ! ! !而小明同學剛好知道怎麼用計算器,於是透過計算機計算得到結果並完成了填空。

計算器的程式碼為:

public class Calculator
 {
  public int add(int a, int b)
  {
   return a + b;
  }
 }

   

修改Student類,新增使用計算機的方法:

public class Student
 {
  private String name = null;
 
  public Student(String name)
  {
   // TODO Auto-generated constructor stub
   this.name = name;
  }
 
  public void setName(String name)
  {
   this.name = name;
  }
 
  @SuppressWarnings("unused")
  private int calcADD(int a, int b)
  {
   return a + b;
  }
 
  private int useCalculator(int a, int b)
  {
   return new Calculator().add(a, b);
  }
 
  public void fillBlank(int a, int b)
  {
   int result = useCalculator(a, b);
   System.out.println(name + "使用计算器:" + a + " + " + b + " = " + result);
  }
 }

   

運行結果如下:


小明使用計算器:168 + 291 = 459


該過程中仍未涉及到回調機制,但是部分小明的部分工作已經實現了轉移,由計算器來協助實現。

3. 幼師回來了

發現小明完成了3位數的加法,​​老師覺得小明很聰明,是個可塑之才。於是又在黑板上寫下了“26549 + 16487 = ”,讓小明上課前完成填空,然後又回辦公室了。

小明看著教室外撒歡兒的小夥伴,不禁悲從中來。再不出去玩,這個課間就要廢了啊! ! ! ! 看著小紅再一次遞上來的計算器,小明心生一計:讓小紅代勞。

小明告訴小紅題目是“26549 + 16487 = ”,然後指出填寫結果的具體位置,然後就出去快樂的玩耍了。

這裡,不把小紅單獨實現出來,而是把這個只能算加法的計算器和小紅看成一個整體,一個會算結果還會填空的超級計算器。這個超級計算器需要傳的參數是兩個加數和要填空的位置,而這些內容需要小明提前告知,也就是小明要把自己的一部分方法暴漏給小紅,最簡單的方法就是把自己的引用和兩個加數一塊告訴小紅。

因此,超級計算器的add方法應該包含兩個運算元和小明自身的引用,程式碼如下:

public class Test
 {
  public static void main(String[] args)
  {
   int a = 168;
   int b = 291;
   Student s = new Student("小明");
   s.fillBlank(a, b);
  }
 }

   

小明這邊現在已經不需要心算,也不需要使用計算器了,因此只需要有一個方法可以向小紅尋求幫助就行了,程式碼如下:

public class SuperCalculator
 {
  public void add(int a, int b, Student xiaoming)
  {
   int result = a + b;
   xiaoming.fillBlank(a, b, result);
  }
 }

   

測試程式碼如下:

public class Student
 {
  private String name = null;
 
  public Student(String name)
  {
   // TODO Auto-generated constructor stub
   this.name = name;
  }
 
  public void setName(String name)
  {
   this.name = name;
  }
 
  public void callHelp (int a, int b)
  {
   new SuperCalculator().add(a, b, this);
  }
 
  public void fillBlank(int a, int b, int result)
  {
   System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result);
  }
 }

   

的小紅

public class Test
 {
  public static void main(String[] args)
  {
   int a = 26549;
   int b = 16487;
   Student s = new Student("小明");
   s.callHelp(a, b);
  }
 }
16487 = 43036


執行流程為:小明透過自身的callHelp方法呼叫了小紅(new SuperCalculator())的add方法,在呼叫的時候將自身的引用(this)當做參數一併傳入,小紅在使用計算機得出結果之後,回調了小明的fillBlank方法,將結果填在了黑板上的空格里。

燈燈燈!到這裡,回呼功能就正式登場了,小明的fillBlank方法就是我們常說的回呼函數。

通过这种方式,可以很明显的看出,对于完成老师的填空题这个任务上,小明已经不需要等待到加法做完且结果填写在黑板上才能去跟小伙伴们撒欢了,填空这个工作由超级计算器小红来做了。回调的优势已经开始体现了。

第4章. 门口的婆婆

幼稚园的门口有一个头发花白的老婆婆,每天风雨无阻在那里摆着地摊卖一些快过期的垃圾食品。由于年纪大了,脑子有些糊涂,经常算不清楚自己挣了多少钱。有一天,她无意间听到了小明跟小伙伴们吹嘘自己如何在小红的帮助下与幼师斗智斗勇。于是,婆婆决定找到小红牌超级计算器来做自己的小帮手,并提供一包卫龙辣条作为报酬。小红经不住诱惑,答应了。

回看一下上一章的代码,我们发现小红牌超级计算器的add方法需要的参数是两个整型变量和一个Student对象,但是老婆婆她不是学生,是个小商贩啊,这里肯定要做修改。这种情况下,我们很自然的会想到继承和多态。如果让小明这个学生和老婆婆这个小商贩从一个父类进行继承,那么我们只需要给小红牌超级计算器传入一个父类的引用就可以啦。

不过,实际使用中,考虑到java的单继承,以及不希望把自身太多东西暴漏给别人,这里使用从接口继承的方式配合内部类来做。

换句话说,小红希望以后继续向班里的小朋友们提供计算服务,同时还能向老婆婆提供算账服务,甚至以后能够拓展其他人的业务,于是她向所有的顾客约定了一个办法,用于统一的处理,也就是自己需要的操作数和做完计算之后应该怎么做。这个统一的方法,小红做成了一个接口,提供给了大家,代码如下:

public interface doJob
 {
  public void fillBlank(int a, int b, int result);
 }

   

因为灵感来自帮小明填空,因此小红保留了初心,把所有业务都当做填空(fillBlank)来做。

同时,小红修改了自己的计算器,使其可以同时处理不同的实现了doJob接口的人,代码如下:

public class SuperCalculator
 {
  public void add(int a, int b, doJob customer)
  {
   int result = a + b;
   customer.fillBlank(a, b, result);
  }
 }

   

小明和老婆婆拿到这个接口之后,只要实现了这个接口,就相当于按照统一的模式告诉小红得到结果之后的处理办法,按照之前说的使用内部类来做,代码如下:
小明的:

public class Student
 {
  private String name = null;
 
  public Student(String name)
  {
   // TODO Auto-generated constructor stub
   this.name = name;
  }
 
  public void setName(String name)
  {
   this.name = name;
  }
 
  public class doHomeWork implements doJob
  {
 
   @Override
   public void fillBlank(int a, int b, int result)
   {
    // TODO Auto-generated method stub
    System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result);
   }
 
  }
 
  public void callHelp (int a, int b)
  {
   new SuperCalculator().add(a, b, new doHomeWork());
  }
 }

   

老婆婆的:

public class Seller
{
 private String name = null;
 
 public Seller(String name)
 {
  // TODO Auto-generated constructor stub
  this.name = name;
 }
 
 public void setName(String name)
 {
  this.name = name;
 }
 
 public class doHomeWork implements doJob
 {
 
  @Override
  public void fillBlank(int a, int b, int result)
  {
   // TODO Auto-generated method stub
   System.out.println(name + "求助小红算账:" + a + " + " + b + " = " + result + "元");
  }
 
 }
 
 public void callHelp (int a, int b)
 {
  new SuperCalculator().add(a, b, new doHomeWork());
 }
}

   

测试程序如下:

public class Test
{
 public static void main(String[] args)
 {
  int a = 56;
  int b = 31;
  int c = 26497;
  int d = 11256;
  Student s1 = new Student("小明");
  Seller s2 = new Seller("老婆婆");
 
  s1.callHelp(a, b);
  s2.callHelp(c, d);
 }
}

   

运行结果如下:

小明求助小红计算:56 + 31 = 87

老婆婆求助小红算账:26497 + 11256 = 37753元

总结

可以很明显的看到,小红已经把这件事情当做一个事业来做了,看她给接口命的名字doJob就知道了。

有人也许会问,为什么老婆婆摆摊能挣那么多钱? 你的关注点有问题好吗!!这里聊的是回调机制啊!!

我只知道,后来小红的业务不断扩大,终于在幼稚园毕业之前,用挣到的钱买了人生的第一套房子。

以上就是本文对于Java中的回调机制(CallBack) 的有趣详解,希望给大家学习java有所帮助。也谢谢大家对PHP中文网的支持。

更多妙解Java中的回调机制(CallBack)相关文章请关注PHP中文网!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn