lambda和匿名內部類使用外部變量為什么要語義final?


今天群里討論javalambda實現.
后來不斷衍生談到了為什么lambda和匿名內部類只能使用語義final的外部變量.

最開始以為是java的lambda實現問題,編譯期魔法會把外部引用作為參數傳入所以在內部變化也影響不了下次調用的值,所以就干脆final了,如果用類的屬性來保管這個變量就可以了.

In [64]:  def outer(a:int):
    ...:      def inner():
    ...:          nonlocal a
    ...:          a = a + a
    ...:          return a
    ...:      return inner
    ...:

In [65]: x = outer(1)

In [66]: x
Out[66]: <function __main__.outer.<locals>.inner>

In [67]: x()
Out[67]: 2

In [68]: x()
Out[68]: 4

In [69]: x()
Out[69]: 8

舉例就是這種情況
lambda用參數傳入外部int,如果在方法里修改了,下次調用這個lambda依舊是以前的值.

后來又去看了眼匿名內部類的實現

public class InnerTest {

    public static void main(String[] args) {
        String name = "123";
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(name);
            }
        };
        r.run();
    }
}
 InnerTest$1(java.lang.String val$name);
     0  aload_0 [this]
     1  aload_1 [val$name]
     2  putfield InnerTest$1.val$name : java.lang.String [12]
     5  aload_0 [this]
     6  invokespecial java.lang.Object() [14]
     9  return
      Line numbers:
        [pc: 0, line: 1]
        [pc: 5, line: 11]
      Local variable table:
        [pc: 0, pc: 10] local: this index: 0 type: new InnerTest(){}
      Method Parameters:
        final synthetic val$name

構造方法字節碼明明都存下來了呀...為什么那時候就要求final

查閱了一下,發現這樣有個很大的問題.
這個外部變量在匿名內部類初始化之后就被固定了下來,之后他如果被重新賦值(引用類型內部狀態修改除外),就會出現內部無法看見外部,外部也無法看見內部的問題... ...
舉個簡單的例子:

In [101]: def outer(x):
     ...:     def inner():
     ...:         nonlocal x
     ...:         x = x+1
     ...:         print("inner"+str(x))
     ...:     inner()
     ...:     print("outer"+str(x))
     ...:     x = x+1
     ...:     inner()
     ...:

In [102]: outer(1)
inner2(inner內部+1)
outer2(外部看到這個變化)
inner4(外部+1 內部+1)

這段在py下能正常工作的代碼,如果java沒有final限制的話,就會變成

inner2(inner內部+1)
outer1(外部看不到inner變化)
inner3(inner內部+1)

所以這個約定和閉包實現沒關系...
還是考慮在定義變量的作用域下規避掉因為java實現問題導致上面的結果返回...我既然沒有nonlocal這樣的機制(畢竟不支持引用傳遞....),索性就用final限制起來.

嗚呼哀哉


參考資料:

https://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class

Closure_(computer_programming)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM