為什么匿名內部類只能訪問其所在方法中的final類型的局部變量?


 

  大部分時候,類被定義成一個獨立的程序單元。在某些情況下,也會把一個類放在另一個類的內部定義,這個定義在其他類內部的類就被稱為內部類,包含內部類的類也被稱為外部類。

class Outer {

    private int a;
public class Inner { private int a; public void method(int a) { a++;      // 局部變量 this.a++;   // Inner類成員變量 Outer.this.a++; // Outer類成員變量 } } }

 

 

  對於上面的成員內部類,一般做法是在Outer中寫一個返回Inner類對象的方法

public Inner getInner() {
    return new Inner();
}

 

  在其他類中使用該成員內部類:

Outer outer = new Outer();
Outer.Inner inner = outer.getInner();
// 或者Outer.Inner inner = outer.new Inner();

 

  而對於靜態內部類,就不需要創建外部類的實例了:

Outer.StaticInner inner = new Outer.StaticInner();

 

 

  匿名內部類不能訪問外部類方法中的局部變量,除非該變量被聲明為final類型

  1. 這里所說的“匿名內部類”主要是指在其外部類的成員方法內定義的同時完成實例化的類,若其訪問該成員方法中的局部變量,局部變量必須要被final修飾。原因是編譯器實現上的困難:內部類對象的生命周期很有可能會超過局部變量的生命周期
  2. 局部變量的生命周期:當該方法被調用時,該方法中的局部變量在棧中被創建,當方法調用結束時,退棧,這些局部變量全部死亡。而內部類對象生命周期與其它類對象一樣:自創建一個匿名內部類對象,系統為該對象分配內存,直到沒有引用變量指向分配給該對象的內存,它才有可能會死亡(被JVM垃圾回收)。所以完全可能出現的一種情況是:成員方法已調用結束,局部變量已死亡,但匿名內部類的對象仍然活着。
  3. 如果匿名內部類的對象訪問了同一個方法中的局部變量,就要求只要匿名內部類對象還活着,那么棧中的那些它要所訪問的局部變量就不能“死亡”。
  4. 解決方法:匿名內部類對象可以訪問同一個方法中被定義為final類型的局部變量。定義為final后,編譯器會把匿名內部類對象要訪問的所有final類型局部變量,都拷貝一份作為該對象的成員變量。這樣,即使棧中局部變量已經死亡,匿名內部類對象照樣可以拿到該局部變量的值,因為它自己拷貝了一份,且與原局部變量的值始終保持一致(final類型不可變)。

 

  最后,Java 8更加智能:如果局部變量被匿名內部類訪問,那么該局部變量相當於自動使用了final修飾

 


免責聲明!

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



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