匿名內部類為什么訪問外部類局部變量必須是final的?


1. 內部類里面使用外部類的局部變量時,其實就是內部類的對象在使用它,內部類對象生命周期中都可能調用它,而內部類試圖訪問外部方法中的局部變量時,外部方法的局部變量很可能已經不存在了,那么就得延續其生命,拷貝到內部類中,而拷貝會帶來不一致性,從而需要使用final聲明保證一致性。說白了,內部類會自動拷貝外部變量的引用,為了避免:1. 外部方法修改引用,而導致內部類得到的引用值不一致 2.內部類修改引用,而導致外部方法的參數值在修改前和修改后不一致。於是就用 final 來讓該引用不可改變。

 

2. 內部類通常都含有回調,引用那個匿名內部類的函數執行完了就沒了,所以內部類中引用外面的局部變量需要是final的,這樣在回調的時候才能找到那個變量,而如果是外圍類的成員變量就不需要是final的,因為內部類本身都會含有一個外圍了的引用(外圍類.this),所以回調的時候一定可以訪問到。例如:

private Animator createAnimatorView(final View view, final int position) {
    MyAnimator animator = new MyAnimator();
    animator.addListener(new AnimatorListener() {
        @Override
        public void onAnimationEnd(Animator arg0) {
            Log.d(TAG, "position=" + position); 
        }
    });
    return animator;
}

內部類回調里訪問position的時候createAnimatorView()早就執行完了,position如果不是final的,回調的時候肯定就無法拿到它的值了,因為局部變量在函數執行完了以后就被回收了。

3. 我們反編譯看一下,首先定義接口和匿名內部類:

public interface MyInterface {
    void doSomething();
}


public class TryUsingAnonymousClass {
    public void useMyInterface() {
        final Integer number = 123;
        System.out.println(number);

        MyInterface myInterface = new MyInterface() {
            @Override
            public void doSomething() {
                System.out.println(number);
            }
        };
        myInterface.doSomething();

        System.out.println(number);
    }
}

我們進行反編譯,結果是:

class TryUsingAnonymousClass$1
        implements MyInterface {
    private final TryUsingAnonymousClass this$0;
    private final Integer paramInteger;

    TryUsingAnonymousClass$1(TryUsingAnonymousClass this$0, Integer paramInteger) {
        this.this$0 = this$0;
        this.paramInteger = paramInteger;
    }

    public void doSomething() {
        System.out.println(this.paramInteger);
    }
}

 

可以看到名為number的局部變量是作為構造方法的參數傳入匿名內部類的。

如果Java允許匿名內部類訪問非final的局部變量的話,那我們就可以在TryUsingAnonymousClass$1中修改paramInteger,但是這不會對number的值有影響,因為它們是不同的reference。

這就會造成數據不同步的問題。

所以,Java為了避免數據不同步的問題,做出了匿名內部類只可以訪問final的局部變量的限制。

參考:http://cuipengfei.me/blog/2013/06/22/why-does-it-have-to-be-final/


免責聲明!

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



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