1. 程式人生 > >Java—內部類(二)—實現閉包與回撥

Java—內部類(二)—實現閉包與回撥

前言:

Java的閉包與回撥我也是第二次接觸這個概念,之前在自學Android的時候繪製View很多地方都用到了監聽器回撥,一直不是很明白,現在回頭鞏固Java的基礎總算的弄明白,儘量用我自己理解的語言來和大家分享,希望對不懂的朋友可以有一定的幫助,大神也可以給我一點指點。

概念:

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

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

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

例項:

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

interface Incrementable{
    void increment();
}

class Callee1 implements Incrementable{
    private int i = 0;
    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; public void increment(){ super.increment(); i++; System.out.println(i); } private class Closure implements Incrementable{ 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的閉包與回撥機制,結合後面的內容會有更多意想不到的作用~