1. 程式人生 > >java中的閉包與回撥

java中的閉包與回撥

閉包(closure)是一個可呼叫的物件,它記錄了一些資訊,這些資訊來自於建立它的作用域。通過這個定義,可以看出內部類是面向物件的閉包,因為它不僅包含外圍類物件(建立內部類的作用域)的資訊,還自動擁有一個指向此外圍類物件的引用,在此作用域內,內部類有權操作所有的成員,包括private成員。

Java最引人爭議的問題之一就是,人們認為Java應該包含某種類似指標的機制,以允許回撥(callback)。通過回撥,物件能夠攜帶一些資訊,這些資訊允許它在稍後的某個時刻呼叫初始的物件。稍後將會看到這是一個非常有用的概念。如果回撥是通過指標實現的,那麼就只能寄希望於程式設計師不會誤用該指標。然而,您應該已經瞭解到,Java更小心仔細,所以沒有在語言中包括指標。通過內部類提供閉包的功能是優良的解決方案,它比指標更靈活、更安全。見下例:

package innerclass;

interface Incrementable {
    void increment();
}

class Callee1 implements Incrementable {
    private int i = 0;

    public void increment() {
        i++;
        System.out.println(i);
    }
}

class MyIncrement {
    void increment() {
        System.out.println("other increment"
); } static void f(MyIncrement mi) { mi.increment(); } } class Callee2 extends MyIncrement { 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 callbackRefference; Caller(Incrementable cbh) { callbackRefference = cbh; } void go() { callbackRefference.increment();// 呼叫increment()方法 } } public class Callbacks { public static void main(String[] args) { Callee1 c1 = new Callee1(); Callee2 c2 = new Callee2(); MyIncrement.f(c2); Caller caller1 = new Caller(c1); Caller caller2 = new Caller(c2.getCallbackReference());// 將內部類中的Closure賦給Caller caller1.go(); caller1.go(); caller2.go(); caller2.go(); } }

輸出結果:

other increment
1
1
2
other increment
2
other increment
3

這個例子進一步展示了外圍類實現一個介面與內部類實現此介面之間的區別。就程式碼而言,Callee1是簡單的解決方式。Callee2繼承自MyIncrement,後者已經有了一個不同的increment()方法,並且與Incrementable介面期望的increment()方法完全不相關。

所以如果Callee2繼承了MyIncrement,就不能為了Incrementable的用途而覆蓋increment()方法,於是只能使用內部類獨立地實現Incrementable。還要注意,當建立了一個內部類時,並沒有在外圍類的介面中新增東西,也沒有修改外圍類的介面。

注意,在Callee2中除了getCallbackReference()以外,其他成員都是private的。要想建立與外部世界的任何連線,interface Incrementable都是必需的。在這裡可以看到,interface是如何允許介面與介面的實現完全獨立的。

內部類Closure實現了Incrementable,以提供一個返Callee2的“鉤子”(hook)——而且是一個安全的鉤子。無論誰獲得此Incrementable的引用,都只能呼叫increment(),除此之外沒有其他功能(不像指標那樣,允許您做很多事情)。

Caller的構造器需要一個Incrementable的引用作為引數(雖然可以在任意時刻捕獲回撥引用),然後在以後的某個時刻,Caller物件可以使用此引用回撥Callee類。

回撥的價值在於它的靈活性——可以在執行時動態地決定需要呼叫什麼方法。

以上來自:《java程式設計思想第四版》

回撥的基本原理跟好萊塢原則一樣,Don’t call me,I’ll call you.

程式設計上來說,一般使用一個庫或類時,是你主動呼叫人家的API,這個叫Call,有的時候這樣不能滿足需要,需要你註冊(注入)你自己的程式(比如一個物件),然後讓人家在合適的時候來呼叫你,這叫Callback。設計模式中的Observer就是例子:所有的觀察者都需要向自己關心的主題Observable註冊,然後主題在適當時機(主題類物件的屬性發生變化時)通知所有訂閱它的觀察者並更新,其中觀察者都實現了一個統一的Observer介面中的Update方法。

回撥實質上是指一個類儘管實際上實現了某種功能,但是沒有直接提供相應的介面,客戶類可以通過這個類的內部類的介面來獲得這種功能。而這個內部類本身並沒有提供真正的實現,僅僅呼叫外部類的實現。可見,回撥充分發揮了內部類所具有的訪問外部類的實現細節的優勢。

相關推薦

java

閉包(closure)是一個可呼叫的物件,它記錄了一些資訊,這些資訊來自於建立它的作用域。通過這個定義,可以看出內部類是面向物件的閉包,因為它不僅包含外圍類物件(建立內部類的作用域)的資訊,還自動擁有一個指向此外圍類物件的引用,在此作用域內,內部類有權操作所有的

java所謂的

之所以覺得javascript寫起來特別的爽,尤其是在編寫非同步程式的時候,是因為javascript的閉包,使得我們能夠簡單的寫出非同步回調回調函式。。。。所以node.js的非同步程式設計也能很簡單的實現。。 在伺服器端程式設計方面,高效能十分依賴非阻塞,非同步和回撥,

Java—內部類(二)—實現

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

java基礎-------

                     閉包是一種能被呼叫的物件,它儲存了建立它的作用域資訊,java7中沒有顯示的支援閉包,但對於非靜態的內部類而言,它不僅記錄了其外部類的資訊,還保留了一個建立非靜態內部類物件的引用,並且可以直接回調外部類的private成員因此可以把

初學Java,(二十一)

閉包在Javascript中用的比較多,Java不顯式支援閉包,但對於非靜態內部類而言,它記錄了其外部類的詳細資訊,還保留了一個建立非靜態內部類物件的引用,並且可以直接呼叫外部類的private成員,因此可以把非靜態內部類當成面向物件領域的閉包。通過這種仿閉包的非靜態內部類,

JavaScript踩坑筆記09---函式

閉包: 簡單點說,閉包就是一個倉庫,它的作用就是將我們要用的區域性變數暫時儲存起來。 舉例說明。 // 定義一個函式fn,其中有一個區域性變數num function fn() { var num = 10; } 以上例子中,我們在函式fn中定義了一個變數num,所以變數的n

總結-全域性環境&執行流程&錯誤型別&垃圾回收機制&&函式&函式

全域性環境&執行流程&錯誤型別&垃圾回收機制&閉包&函式&回撥函式 全域性環境 1.函式中的this表示改函式所屬的物件 2.window物件的成員在呼叫時可以省略window 執行流程 1.編譯程式碼:當前scr

javascript分析函式

<div id="box1">First Box</div> <div id="box2">Second Box</div> <script> function animateIt(elementId) { var el

java 運用 實現方法傳遞

寫了一個測試java閉包的例項,在事件監聽中用得比較多的設計模式!定義一個介面,通過介面來傳遞方法體/** * @author yaohw * */ public interface Action{ public void excute(Object arg);

Javascript和Java的理解

一。Javascript中閉包: 1.變數的作用域   要理解閉包,首先必須理解Javascript特殊的變數作用域。   變數的作用域無非就是兩種:全域性變數和區域性變數。      Javascript語言的特殊之處,就在於函式內部可以直接讀取全域性變數  var n=

Java程式設計之委託代理、內部類以及匿名內部類()

最近一直在看Java的相關東西,因為我們在iOS開發是,無論是Objective-C還是Swift中,經常會用到委託代理回撥,以及Block回撥或者說是閉包回撥。接下來我們就來看看Java語言中是如何實現委託代理回撥以及閉包回撥的。當然這兩個技術點雖然實現起來並不困難,但是,這回調在封裝一些公用元件時還是特別

13、python的函數(裝飾器)

屬性 新的 做的 一個 too 實現 inf 高級 器) 一、嵌套函數 函數的內部又再定義另一個函數,這個函數就叫嵌套函數,裏面含函數就叫內部函數。 示例: 二、返回函數 函數可以接收函數對象作為參數,同理函數也能返回一個函數對象作為返回值。

vue頁面的功能

HTML中的引用格式: <tp-table ref="branchTab" :all_params="branch_params" @add-btn="addBranch" @del-btn="delShow"></tp-table> script檔案中的方法:

JavaScript立即執行函式

本文是前端學習筆記的第四篇,對應的是渡一教育的web前端開發JavaScript精英課js的第十三到十五課時,感覺難度還可以,閉包其實非常類似Java中的方法內部類,對比一下就很好理解了,主要就是記的知識點多,可能會忘 目錄 閉包 立即執行函式   閉包 &

javajar的生成使用

什麼是jar包? JAR檔案的全稱是Java Archive File,意思是Java檔案檔案。是一種壓縮檔案,與常見的ZIP壓縮檔案相容。兩者最大的區別是在JAR檔案中預設包含一個名為META-INF/MANIFEST.MF的清單檔案,這個檔案是生成JAR檔案時由系統自動建立的。 使用

python函式裝飾器函式

閉包 首先知道閉包函式的語法特徵: 函式巢狀定義 外部函式返回內部函式的引用 內部函式可以呼叫外部函式的自由變數 外部函式的作用是建立內部函式並且返回內部函式的引用。 def line(k, b): """外部函式的作用: 建立內部函式並且返回內部函式的引用

C#的名稱空間namespaceJavapackage之間的區別

Java 包被用來組織檔案或公共型別以避免型別衝突。包結構可以對映到檔案系統。 System.Security.Cryptography.AsymmetricAlgorithm aa; 可能被替換: import System.Security.Crypography; class xxx { .

python 函式的區別

定義:(重點在定義) 在外部函式裡面定義一個內部函式,並且這個內部函式用到了外部函式的變數,那麼將這個內部函式和用到的一些變數統稱為閉包。 首先看一個閉包的例項: def lines(a, b):

迴圈的函式

1.es5中的函式迴圈遍歷 由於在es5中沒有塊級作用域,會導致一些問題 //迴圈中的函式 var func = []; //這是個陣列 for(var i=0;i<10;i++){ console.log(i);//列印了

淺談Java 7的Lambda表示式之優劣

前幾天Oracle推出了Java 7官方的閉包與Lambda表示式的第一個實現,這基本上也是最終在正式版中的樣式了。看了這個實現之後,我的第一感覺便是“醜”,當然不排除這是因為看慣了其他語言中實現的緣故。後來再仔細看了看又想了想,發現Java 7的實現也並非毫無可取之處,但似乎又感到某些做法上有一些問