首頁  >  文章  >  Java  >  再談java回呼函數

再談java回呼函數

高洛峰
高洛峰原創
2017-01-24 13:41:191027瀏覽

又遇到了回呼函數,這次打算寫下來分享一下。

所謂回呼函數,或是在物件導向語言裡叫回呼方法,簡單點講,就是回頭在某個時間(事件發生)被呼叫的函數。

再詳細點:就是一個函數A,作為參數,傳入了另一個函數B,然後被B在某個時間呼叫。

這裡可以有疑問了,既然是一個函數調用另一個函數,可以在函數體裡面調用啊,為什麼還要把函數作為參數傳到另一個函數裡被調用?何況還有一些語言(比如java)不支援把函數當作參數。

對的,確實可以在函數體裡呼叫另一個函數,功能上好像是沒差別的,但是這裡有一個問題,就是你要調用的這個函數被寫死了,也就是說這樣函數B只能呼叫函數A了,這樣如果在另一個情境下,有個與A不同實現的函數C也需要在B的某個時刻被調用,那怎麼辦。

下面繼續說回調函數,在c/c++裡,回呼函數可以使用函數指標作為參數被另一個函數呼叫;在c#裡,可以使用委託,如果是事件方法的話,還有event關鍵字;在python和javascript裡,可以直接把函數當對象傳參,這些語言都很好實現回調函數(方法),可是, java呢? 先說點題外話,自從學了C#,就不喜歡java了,曾經一度打算以後不再用java,可是現實並沒有那麼理想,我現在要做android,所以還是不能放下java,而且今天遇到這個回調函數的問題,也是從java裡遇到的,我個人覺得,在這個博客裡出現的語言,除了java外,對於回調,都可以既容易,又好理解的實現,但是java,我覺得並不是那樣,不然我也不會來寫這篇博客。

好了繼續說,關於java中的回調方法的實作。這篇部落格的重點就是說java的。 在java中,回呼方法是用借用接口來實現的,我在網上找到一句話:

“把實現某一接口的類所創建的對象的引用,賦值給該​​接口聲明的接口變量,那麼該接口變數就可以呼叫被實現的介面的方法」。
很繞哈,簡單解釋下:
有一個接口,接口裡有一個方法(這個方法就是要回調的方法):

interface CallBackInterface {
  void callBackMethod();
}

我們知道,接口對像不能直接用,因為裡面的方法都沒有實現。所以要找個類別實作這個介面。
所以現在加一個類,實現這個接口:

interface CallBackInterface {
  void callBackMethod();
}
 
class CallBackClass implements CallBackInterface{
 
  @Override
  public void callBackMethod() {
    System.out.println("hello");
  }
}

   

好了,最後一步:把實現了接口的類的對象賦值給聲明的接口變量(我給寫進一個方法裡了,然後外面加了個類的殼子):

public class CallBackTest {
 
  interface CallBackInterface {
    void callBackMethod();
  }
 
  class CallBackClass implements CallBackInterface {
 
    @Override
    public void callBackMethod() {
      System.out.println("hello");
    }
  }
 
  public void showCallBack() {
    CallBackInterface itfs = new CallBackClass();
    itfs.callBackMethod();
  }
}

   

現在可以調用試試看了:

public class Test {
  public static void main(String[] args) {
    new CallBackTest().showCallBack();
  }
}

沒意外的話,會成功輸出hello,反正例子我這一邊是的.所以說我做了什麼? 再詳細點說,我們有一個要在某一個方法裡被調用的方法(這個方法就是回調方法), 前面我們也說了,最好不要直接把想要回調方法做的事直接寫在呼叫方法裡, 又因為java裡沒辦法把方法當做參數傳遞,所以我們只好把這個回調方法放在了接口裡(為什麼不是類?不是抽象類?而是接口?你可以自己去找下抽象類別與介面的異同,自己解決這個問題)。有介面的話,就要被類別實現,然後,只要是給介面的物件賦予實現類別的對象,這個介面的對象就可以呼叫那個方法了。理解這裡的話,有一個重點,就是多態, 這裡用到的多態知識就是,介面的物件可以順利被子類別賦值,並且呼叫子類別的重寫方法(類別也有類似的概念)。

再多說一點,這裡任何實作了CallbackInterface介面的類,都可以像下面這樣放在new後面(就是賦值):

public class CallBackTest {
  interface CallBackInterface {
    void callBackMethod();
  }
 
  class CallBackClass implements CallBackInterface {
 
    @Override
    public void callBackMethod() {
      System.out.println("hello");
    }
  }
 
  class Controller {
    private CallBackInterface cbitf;
    // 这个boolean只是为了模拟有事件,没啥实用价值
    public boolean somethingHappend;
    // 这里确实可以直接把CallBackClass做参数,而且省掉接口的定义
    // 但是这样做的话,就像是回调函数直接写在了调用函数里一样
    // 不明白的话就好好理解下"约定"和"调用者不管回调函数是怎么实现的"吧
    public Controller(CallBackInterface itfs) {
      somethingHappend = true;
      this.cbitf = itfs;
    }
 
    public void doSomething() {
      if(somethingHappend) {
        cbitf.callBackMethod();
      }
    }
  }
 
  public void showCallBack() {
    CallBackClass cbc = new CallBackClass();
    Controller ctrlr = new Controller(cbc);
    ctrlr.doSomething();
    // 其实上面也可以这样写在一行里
    // new Controller(new CallBackClass()).doSomething();
  }
}

   

最後多說一點,其實常常遇到,就是在學android的時候遇到的。

以上就是個人對於回呼函數的理解與使用方法了,希望大家能夠喜歡。

更多再談java回呼函數相關文章請關注PHP中文網!

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