Java—內部類實現閉包與回調

概念:  

我覺得在理解一個事物之前,需要對這個事物在我們的大腦裏有一個初步的概念,然後再對這個概念補充上細節,這是我在理解一些陌生事物的時候的一個方法,也可以說是類比理解法吧。先說閉包~

一.閉包 
閉包,故名思意就是,把一個包關起來,那麼對於Java來說,這個包就是類了,因爲在java中任何事物都是類,都是對象。那麼閉包,直接理解上就是把一個類封裝起來(封裝就是包裝差不多的意思)。然後結合一下,閉包內容放在內部類中,所以閉包就是用一個類把另一個類包裝起來,說起來這和內部類沒有什麼不同點啊,爲啥要專門用一個詞來表述它呢?因爲這個閉包還有很多其他的作用。而且其構造要比內部類複雜一點,先說說它的作用,作用有二~ 
1. 閉包能夠保護內部類裏面的變量安全,不會被外部訪問 
2. 閉包能夠維持一個變量一直存活在內存中,不被CG(垃圾回收機制)回收掉 
在構造上,內部類需要提供一個給外部調用它的接口,這樣才能在維持住內部類的同時,因爲內部類攜帶了外部類的信息,所以外部類也得以存活。

二.回調 
回調直接理解就是回頭調用,先將相關的方法實現好,但是並不由我來決定什麼時候來調用它,而是等到一個時候,程序自己回頭調用這個方法,而實現回調機制,這可以說是一種設計模式,而不僅僅是一個語言上的特性。與回調相關的概念還有同步調用,與異步調用,同步調用即單向調用,調用方等待對方執行完成後才返回。異步調用則類似消息機制,等待收到一定的消息後執行某些操作,回調與異步調用有一些共同之處,現在理解的還不是很清楚,先埋下一坑,以後清楚了在補一篇。

實例:
接下來就直接上代碼分析,讓大家補充一些細節上的理解,來清楚整個過程,整個過程相當於我的口述,如有不對的地方,希望大家指出:

interface Incrementable{
    void increment();
}

class Callee1 implements Incrementable{
    private int i = 0;
    @Override
    public void increment(){
        i++;
        System.out.println(i);
    }
}

class MyIncrementable {
    public void increment(){ System.out.println("Other Operarion"); }
    static void f(MyIncrementable mi){ mi.increment(); }
}

class Callee2 extends MyIncrementable{
    private int i = 0;
    @Override
    public void increment(){
        super.increment();
        i++;
        System.out.println(i);
    }
    private class Closure implements Incrementable{
        @Override
        public void increment(){
            Callee2.this.increment();
        }
    }
    Incrementable getCallbackReference(){
        return new Closure();
    }
}

class Caller{
    private Incrementable callbackReference;
    Caller(Incrementable cbn){ callbackReference = cbn; }
    void go(){ callbackReference.increment(); }
}

public class Callbacks {
    public static void main(String[] args){
        Callee1 c1 = new Callee1();
        Callee2 c2 = new Callee2();
        MyIncrementable.f(c2);
        Caller caller1 = new Caller(c1);
        Caller caller2 = new Caller(c2.getCallbackReference());
        caller1.go();
        caller1.go();
        caller2.go();
        caller2.go();
    }

}

這個是java編程思想上很經典的一個例子。輸出是這樣的:

Other Operarion
1
1
2
Other Operarion
2
Other Operarion
3

希望大家首先自己通讀一下代碼,然後理解一下程序輸出結果爲什麼是這樣的,這樣有助於我們去理解之前所說的閉包與回調機制。

這裏我默認大家看完了,我來說一下我的理解: 
首先Callee1是一個簡單的實現了接口Incrementable與相關方法,在這裏起到一個對比的作用而已。然後實現了一個MyIncrement類同樣實現了一個increment()方法但是這個與接口中的increment()沒有任何關係,因爲這個類自己實現的,並沒有實現這個接口,而靜態方法f()也只是爲了測試一下increment()方法。而Callee2繼承自這個類。這裏就是重點了。同樣寫了一個increment()方法,覆蓋了父類方法,但是中間還是調用了父類方法。接下里是一個內部類也就是閉包的具體實現了。內部類實現了接口Incrementable並且直接調用外部類的方法作爲具體的實現。內部類實現Increment able接口很關鍵,這樣就給外部留下了一個通道,能夠接受這個內部類。最後Callee2的後面留下了一個鉤子,即getCallbackReference()方法,它返回一個內部類的對象,實現了內部與外部的鏈接,同時有保證了內部類的安全,因爲只有Callee2的對象可以訪問與調用這個內部類的方法,而其他的類都無權訪問,即使是基類接口對象。而後面的Caller類起到的是一個喚醒作用,通過接受不同的接口對象,實現不同的操作,但還有一個作用是等待接受一個內部類對象,來產生回調。現在大家再回頭看一下輸出就能夠明白了。

假裝你回頭看了,在main()方法中,首先是創建對象與聲明,然後是調用了一個MyIncrement的靜態方法,傳入的是一個Callee2對象,此時無法觸發回調,所以只是正常的輸出,然後,才Caller2的初始化時傳入的是一個Closure對象從而產生了回掉。

以上就是java的閉包與回調機制,結合後面的內容會有更多意想不到的作用~
 

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