爲何局部內部類和匿名內部類只能訪問 final 的局部變量?

首先,咱們看一個局部內部類的例子: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

相關文章
相關標籤/搜索