java爲何匿名內部類的參數引用時final(轉)

https://blog.csdn.net/z69183787/article/details/68490440編程

 

https://www.zhihu.com/question/21395848跨域

https://www.zhihu.com/question/24084277/answer/110176733閉包

喜歡看生肉的同窗就不用看個人回答了,直接看R大的三篇回答,尤爲是第一篇後面的回覆部分。編程語言

我只是試着用大白話作個簡單的整理,但願能更容易理解一點。
函數

關於對象與閉包的關係的一個有趣小故事 (這篇的精華在後面的回覆,小故事能夠跳過)
this

JVM的規範中容許編程語言語義中建立閉包(closure)嗎? - RednaxelaFX 的回答.net

爲何Java閉包不能經過返回值以外的方式向外傳遞值? - RednaxelaFX 的回答指針

1. 閉包(Closure)
什麼是閉包,大白話不怎麼嚴謹的說就是:
對象

 

  1. 一個依賴於外部環境自由變量的函數
  2. 這個函數可以訪問外部環境裏的自由變量

看下面這個Javascript閉包的例子:blog

 


對內部函數function(x)來說,y就是自由變量,並且function(x)的返回值,依賴於這個外部自由變量

y。而往上推一層,外圍Add(y)函數正好就是那個包含自由變量y的環境。並且Javascript的語法允

許內部函數function(x)訪問外部函數Add(y)的局部變量。知足這三個條件,因此這個時候,外部函

數Add(y)對內部函數function(x)構成了閉包。

閉包的結構,若是用λ演算表達式來寫,就是多參數的Currying技術。

>λx.λy.x+y

但在Java中咱們看不到這樣的結構。由於Java主流語法不容許這樣的直接的函數套嵌和跨域訪問變量。


2. 類和對象

但Java中真的不存在閉包嗎?正好相反,Java處處都是閉包,因此反而咱們感受不出來在使用閉

包。由於Java的「對象」其實就是一個閉包。其實不管是閉包也好,對象也好,都是一種數據封裝的

手段。看下面這個類


看上去x在函數add()的做用域外面,可是經過Add類實例化的過程,變量」x「和數值」2「之間已經綁

定了,並且和函數add()也已經打包在一塊兒。add()函數實際上是透過this關鍵字來訪問對象的成員字

段的。

若是對閉包有疑問,能夠看這個更詳細的回答:

閉包(計算機科學)是什麼? - 胖胖的回答


3. Java內部類是閉包:包含指向外部類的指針

那Java裏有沒有除了實例對象以外的閉包結構?Java中的內部類就是一個典型的閉包結構。例子以下,


下圖畫的就是上面代碼的結構。內部類(Inner Class)經過包含一個指向外部類的引用,作到自

由訪問外部環境類的全部字段,變相把環境中的自由變量封裝到函數裏,造成一個閉包。



4. 彆扭的匿名內部類

但Java匿名內部類就作得比較尷尬。下面這個例子中,getAnnoInner負責返回一個匿名內部類的引用。


匿名內部類由於是匿名,因此不能顯式地聲明構造函數,也不能往構造函數裏傳參數。不但返回的只是個叫AnnoInner的接口,並且尚未和它外圍環境getAnnoInner()方法的局部變量x和y構成任何類的結構。但它的addXYZ()函數卻直接使用了x和y這兩個自由變量來計算結果。這就說明,外部方法getAnnoInner()事實上已經對內部類AnnoInner構成了一個閉包。

但這裏彆扭的地方是這兩個x和y都必須用final修飾,不能夠修改。若是用一個changeY()函數試圖修改外部getAnnoInner()函數的成員變量y,編譯器通不過,

error: cannot assign a value to final variable y

這是爲何呢?由於這裏Java編譯器支持了閉包,但支持地不完整。說支持了閉包,是由於編譯器編譯的時候其實悄悄對函數作了手腳,偷偷把外部環境方法的x和y局部變量,拷貝了一份到匿名內部類裏。以下面的代碼所示。


因此用R大回答裏的原話說就是:

Java編譯器實現的只是capture-by-value,並無實現capture-by-reference。

而只有後者才能保持匿名內部類和外部環境局部變量保持同步。

但Java又不願明說,只能粗暴地一刀切,就說既然內外不能同步,那就不准你們改外圍的局部變量。


5. 其餘和匿名內部類類似的結構

《Think in Java》書裏,只點出了匿名內部類來自外部閉包環境的自由變量必須是final的。但實際上,其餘幾種不太經常使用的內部類形式,也都有這個特性。

好比在外部類成員方法內部的內部類。


好比在一個代碼塊block裏的內部類。

相關文章
相關標籤/搜索