這是java的一條規則。那麼為什麼會有這條規則呢?要想弄懂這個問題,就需要弄懂局部內部類對象和局部變數的生命周期的誰更長的問題。 首先,看一段代碼,以沒有將變數聲明為final的代碼作為例子,代碼如下: 如上面的第7行代碼所示,變數x沒有被聲明為final,如果是這樣的話,當執行完第26行的outM ...
這是java的一條規則。那麼為什麼會有這條規則呢?要想弄懂這個問題,就需要弄懂局部內部類對象和局部變數的生命周期的誰更長的問題。
首先,看一段代碼,以沒有將變數聲明為final的代碼作為例子,代碼如下:
1 class Outer{ 2 3 Object obj; 4 public void outerMethod() { 5 6 //局部變數 7 int x = 5; 8 //定義在方法中的內部類稱為局部內部類 9 class Inner{ 10 11 public void innerMethod() { 12 System.out.println(x);//訪問了局部變數x 13 } 14 } 15 //創建內部類實例 16 Inner in = new Inner(); 17 in.innerMethod(); 18 //將內部類實例的引用賦值給obj 19 obj = in; 20 } 21 } 22 public class HelloDemo extends Hello{ 23 24 public static void main(String[] argr) { 25 Outer out = new Outer(); 26 out.outerMethod(); 27 } 28 }
如上面的第7行代碼所示,變數x沒有被聲明為final,如果是這樣的話,當執行完第26行的outMethod()方法後,outMethod()方法將出棧,出棧後outMethod()方法裡面定義的所有變數(x 和 in)都死亡了,(但是此時內部類的對象還活著,直到它不再被使用才會被回收,也就是說此內部類對象的生命周期比局部變數的生命周期長),並且在變數 in 死亡之前,in 的值賦值給了全局變數obj(第19行代碼),這時obj 指向了內部類的對象,如果此時執行一條代碼: obj.innerMethod();那麼這條代碼將會訪問到局部變數 x,但是此時 x 已經死亡了,內部類對象已經訪問不到 x 了,因此這是相互矛盾的。所以上面的代碼實際上並不能編譯通過。(在jdk8.0能編譯通過,那是因為它檢測到局部內部類訪問了 x,會預設給 x 的前面加上隱式的final,如果在第8行加上一句代碼:x = 4;編譯器將會報錯,因為final不允許 x 的值改變)
如果局部變數 x 被聲明為final後(在第七行的int前加上final),x 就代表了一個常量,那麼第15行的代碼實際上就變成了 System.out.println(5);,這時內部類相當於訪問了一個數字5。這是沒任何問題的,因此局部內部類訪問它所在方法的局部變數時,要求該局部變數必須聲明為final。究其根本原因,是局部內部類對象的生命周期比局部變數的生命周期長。
2018-05-11 22:10:16