java的閉包

什么是閉包

1、一個含有自由變量的函數(shù);
2、這些自由變量所在的環(huán)境。
也就是函數(shù)和環(huán)境的總和構成一個閉包。外部環(huán)境持有內(nèi)部函數(shù)所使用的自由變量,對內(nèi)部函數(shù)形成“閉包”。
簡單但不嚴格的說,一個函數(shù)的“自由變量”就是既不是參數(shù)也不是局部變量的變量(外部變量)。

一個純粹(無副作用)的函數(shù)如果不含有自由變量,那么每次用相同的參數(shù)調用后的得到的結果肯定是一樣的。但如果一個函數(shù)含有自由變量,那么調用返回的結果不但依賴于參數(shù)的值,還依賴于自由變量的值。因此一個含有自由變量的函數(shù)要正確執(zhí)行,必須保證其所依賴的外圍環(huán)境的存在。
在JS中的樣子如下

function a() { 
  var i = 0; 
  function b() { alert(++i); } 
  return b; 
} 
var c = a(); 
c();      //1 
c();      //2 

閉包和面向對象

閉包與對象是從兩個完全不同的角度描述了一件事情:一段代碼與其環(huán)境的關系。
所以可以用對象來模擬(實現(xiàn))閉包,也可以用閉包來模擬(實現(xiàn))對象。
剛剛閉包里的例子的效果完全可以用對象做出來, 這兩種方式都體現(xiàn)了函數(shù)和環(huán)境之間的關系。

class a {  
    private int i = 0;  
    int b( ) { System.out.priintly(++i); }  
}  
a c = new a();
c.b //1
c.b //2

當然嚴格來說方法所捕獲的自由變量不是i,而是this;i是通過this來訪問到的,完整寫出應該是this.i。

閉包的傳值

讓我們考察下面兩種情況:

  • 只有值捕獲(capture-by-value):只需要在創(chuàng)建閉包的地方把捕獲的值拷貝一份到對象里即可。Java的匿名內(nèi)部類和Java 8新的lambda表達式都是這樣實現(xiàn)的。

  • 有引用捕獲(capture-by-reference):把被捕獲的局部變量“提升”(hoist)到對象里。C#的匿名函數(shù)(匿名委托/lambda表達式)就是這樣實現(xiàn)的。參考Eric Lippert大神對“hoist”一詞的講解。不要把這個“hoist”的用法跟JavaScript里說的把局部變量提前到函數(shù)開頭來聲明的那種用法混為一談。

如果變量(variable)是不可變(immutable)的,那么使用者無法感知值捕獲和引用捕獲的區(qū)別。

  • 有些語言(例如C++11)允許顯式指定捕獲列表以及捕獲方式(值捕獲還是引用捕獲),這樣最清晰,不過寫起來比較長;
  • 有些語言(例如JavaScript)只有引用捕獲,要模擬值捕獲的效果需要手動新建閉包和局部變量;有些語言(例如C#)對不可變量(const local)做值捕獲,對普通局部變量做引用捕獲;由于無法感知對不可變量的值捕獲與引用捕獲的區(qū)別,統(tǒng)一把這個行為描述成是引用捕獲更方便一些。
  • 有些語言(例如Java)雖然目前只實現(xiàn)了值捕獲,但是還要留著面子不承認自己只做了值捕獲,所以只允許捕獲不變量(final local),或者例如Java 8允許捕獲事實上不變量(effectively final local)。這樣,雖然實現(xiàn)用的是值捕獲,但效果看起來跟引用捕獲一樣;就算以后的Java擴展到允許通用的(對可變變量的)引用捕獲,也不會跟已有的代碼發(fā)生不兼容。
public class Test {
    public static void main(String[] args)  {
         
    }
     
    public void test(final int b) {
        final int a = 10;
        new Thread(){
            public void run() {
                System.out.println(a);
                System.out.println(b);
            };
        }.start();
    }
}
  • 有些語言(例如Python)的lambda略奇葩,實現(xiàn)的是引用捕獲,但是lambda內(nèi)不能對捕獲的變量賦值,只有原本定義那些變量的作用域里能對它們賦值。
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容