2010-05-04 205 views
2

您好我正在閱讀關於內部類的SCJP書,並發現這個語句,它是這樣的。方法本地內部類訪問方法的局部變量

的方法,局部類只能引用被標記final

,並在解釋中指定的原因是關於局部類對象的範圍和壽命和局部變量上的局部變量堆,但我無法理解這一點。我在這裏丟失了什麼關於final ??

回答

6

原因是,當創建方法局部類實例時,它所引用的所有方法局部變量實際上都被編譯器複製到其中。這就是爲什麼只有final變量可以被訪問。 A final變量或引用是不可變的,所以它與方法本地對象內的副本保持同步。如果不是這樣,那麼在創建方法本地類之後,原始值/引用可能會改變,讓位於混淆行爲和微妙的錯誤。

考慮從JavaSpecialist newsletter no. 25這個例子:

public class Access1 { 
    public void f() { 
    final int i = 3; 
    Runnable runnable = new Runnable() { 
    public void run() { 
     System.out.println(i); 
    } 
    }; 
    } 
} 

編譯器接通內部類成這樣:

class Access1$1 implements Runnable { 
    Access1$1(Access1 access1) { 
    this$0 = access1; 
    } 
    public void run() { 
    System.out.println(3); 
    } 
    private final Access1 this$0; 
} 

由於i值是最後時,編譯器可以 「內聯」它進入了內心階層。

+0

感謝您對通訊鏈接的明確解釋和thx ..這是非常有幫助的。 – flash 2010-05-04 09:24:43

2

正如我所見,從方法本地類(例如匿名類)訪問局部變量是一件有風險的事情。這是編譯器允許的,但它需要很好地理解發生了什麼。

當內部類被實例化時,它所使用的所有對局部變量的引用都被複制,並作爲隱含的構造函數參數(檢查字節碼)傳遞。實際上,編譯器可以允許使引用不是最終的,但這會讓人困惑,因爲如果方法在實例化之後改變引用將會發生什麼,這並不清楚。

但是,製作參考最終並不能消除所有問題。儘管引用是不可變的,但引用背後的對象仍然可以是可變的。內部類的實例化到內部類的任何突變都會被內部類看到,有時這不是程序員的意圖。