java的閉包

什么是閉包

1、一個含有自由變量的函數(shù)辉巡;
2恨憎、這些自由變量所在的環(huán)境。
也就是函數(shù)和環(huán)境的總和構(gòu)成一個閉包郊楣。外部環(huán)境持有內(nèi)部函數(shù)所使用的自由變量憔恳,對內(nèi)部函數(shù)形成“閉包”。
簡單但不嚴(yán)格的說净蚤,一個函數(shù)的“自由變量”就是既不是參數(shù)也不是局部變量的變量(外部變量)钥组。

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

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

閉包和面向?qū)ο?/h3>

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

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

當(dāng)然嚴(yán)格來說方法所捕獲的自由變量不是i影暴,而是this;i是通過this來訪問到的探赫,完整寫出應(yīng)該是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)不能對捕獲的變量賦值透硝,只有原本定義那些變量的作用域里能對它們賦值狰闪。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市濒生,隨后出現(xiàn)的幾起案子埋泵,更是在濱河造成了極大的恐慌,老刑警劉巖罪治,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丽声,死亡現(xiàn)場離奇詭異,居然都是意外死亡觉义,警方通過查閱死者的電腦和手機雁社,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晒骇,“玉大人霉撵,你說我怎么就攤上這事『槎冢” “怎么了喊巍?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長箍鼓。 經(jīng)常有香客問我崭参,道長,這世上最難降的妖魔是什么款咖? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任何暮,我火速辦了婚禮,結(jié)果婚禮上铐殃,老公的妹妹穿的比我還像新娘海洼。我一直安慰自己,他們只是感情好富腊,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布坏逢。 她就那樣靜靜地躺著,像睡著了一般赘被。 火紅的嫁衣襯著肌膚如雪是整。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天民假,我揣著相機與錄音浮入,去河邊找鬼。 笑死羊异,一個胖子當(dāng)著我的面吹牛事秀,可吹牛的內(nèi)容都是我干的彤断。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼易迹,長吁一口氣:“原來是場噩夢啊……” “哼宰衙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起睹欲,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤供炼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后句伶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劲蜻,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年考余,在試婚紗的時候發(fā)現(xiàn)自己被綠了先嬉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡楚堤,死狀恐怖疫蔓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情身冬,我是刑警寧澤衅胀,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站酥筝,受9級特大地震影響滚躯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嘿歌,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一掸掏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宙帝,春花似錦丧凤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至靴患,卻和暖如春仍侥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蚁廓。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工访圃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人相嵌。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓腿时,卻偏偏與公主長得像,于是被迫代替她去往敵國和親饭宾。 傳聞我的和親對象是個殘疾皇子批糟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354