首先,咱們看一個局部內部類的例子:java
class OutClass { private int age = 12; public void outPrint(final int x) { class InClass { public void InPrint() { System.out.println(x); System.out.println(age); } } new InClass().InPrint(); } }
這裏有一個外部類 OuterClass 和一個內部類 InClass,內部類訪問了外部類的一個方法中的一個局部變量 x,在這裏,x 必須是 final 的,不然會報錯:ide
Cannot refer to a non-final variable x inside an inner class defined in a different method
下面來分析下這個問題:.net
追究其根本緣由就是做用域中變量的生命週期致使的;命令行
首先須要知道的一點是: 內部類和外部類是處於同一個級別的,內部類不會由於定義在方法中就會隨着方法的執行完畢就被銷燬。code
這裏就會產生問題:當外部類的方法結束時,局部變量就會被銷燬了,可是內部類對象可能還存在(只有沒有人再引用它時,纔會死亡)。這裏就出現了一個矛盾:內部類對象訪問了一個不存在的變量。爲了解決這個問題,就將局部變量複製了一份做爲內部類的成員變量,這樣當局部變量死亡後,內部類仍能夠訪問它,實際訪問的是局部變量的"copy"。這樣就好像延長了局部變量的生命週期。咱們能夠經過反編譯生成的 .class 文件來實驗:
在命令行窗口中先執行命令 javac OutClass.java 進行編譯,會獲得兩個文件: OutClass$1InClass.class、OutClass.class:
javap 是 Java class 文件分解器,能夠反編譯,也能夠查看java編譯器生成的字節碼。對象
這裏咱們能夠再執行命令 javap -privateOutClass$1InClass 進行反編譯, -private 表示顯示全部類和成員,執行後會獲得以下結果:
可見方法中的局部變量實際上確實會複製爲內部類的成員變量使用。blog
問題又出現了:將局部變量複製爲內部類的成員變量時,必須保證這兩個變量是同樣的,也就是若是咱們在內部類中修改了成員變量,方法中的局部變量也得跟着改變,怎麼解決問題呢?生命週期
就將局部變量設置爲final,對它初始化後,我就不讓你再去修改這個變量,就保證了內部類的成員變量和方法的局部變量的一致性。這實際上也是一種妥協。作用域
若變量是final時:get
如果基本類型,其值是不能改變的,就保證了copy與原始的局部變量的值是同樣的;
如果引用類型,其引用是不能改變的,保證了copy與原始的變量引用的是同一個對象。
這就使得局部變量與內部類內創建的拷貝保持一致。
原文連接:https://blog.csdn.net/sf_climber/article/details/78326984