ローカル内部クラスはfinalローカル変数にしかアクセスできないのに、メンバー変数に対して勝手にアクセスできるのはなぜですか?

2223 ワード

ローカル内部クラスはfinalローカル変数にしかアクセスできないのに、メンバー変数に対して勝手にアクセスできるのはなぜですか?
public class OuterClass {
	private int memberField = 10;
	
	public void outerDo(){
		final int localField = fromOther();
		
		class InnerClass{
			public void innerDo(){
				memberField = localField;
			}
		};
	}

	private int fromOther() {
	    return 20;
    }
}
 
ローカル変数とメンバー変数は、内部クラスにとって一定の共通性を有し、いずれもその内部クラスの外の変数である.内部クラスがfinalのローカル変数にのみアクセスできることを要求するのは、ローカル変数が変更されないようにするためであれば、内部クラスアクセスメンバー変数にも同様の制限があるはずです.
 
 
彼らの生存範囲がこの違いを招いたと思います.
まず、内部クラスのインスタンスは、メソッドの終了後も生存することができ、ローカル変数はメソッドの終了後も生存できないため、内部クラスではNON-finalのローカル変数にアクセスできない.
メンバー変数の生存時間は、外部クラスのインスタンスに依存し、内部クラスインスタンスでは現在の外部クラスインスタンスが参照されるため、一貫したライフサイクルがあり、メンバー変数にアクセスできます.
 
残りの問題は、finalのローカル変数にアクセスできる理由です.
finalにアクセスした局所変数の内部クラスを逆コンパイルすると,その変数は構造関数としてのパラメータによって伝達され,それとともに伝達されたパラメータと外部クラスインスタンスがあることが分かった.
......
com.study.innerclass.OuterClass$1InnerClass(com.study.innerclass.OuterClass, int);   Code:    Stack=2, Locals=3, Args_size=3    0:    aload_0    1:    aload_1    2:    putfield    #12;//Field this$0:Lcom/study/innerclass/OuterClass;    5:    aload_0    6:    iload_2    7:    putfield    #14;//Field val$localField:I    10:    aload_0    11:    invokespecial    #16;//Method java/lang/Object."":()V    14:    return   LineNumberTable:    line 9: 0   LocalVariableTable:    Start  Length  Slot  Name   Signature    0      15      0    this       Lcom/study/innerclass/OuterClass$1InnerClass;
 
 
Javacがこのように内部クラスを処理している以上、これは内部クラスにパラメータ付きの構造関数を提供することと変わらない.
public class OuterClass {
	private int memberField = 10;
	
	public void outerDo(){
		int localField = fromOther();
		
		class InnerClass{
			private int local;
			public InnerClass(int local) {
				this.local = local;
            }
			public void innerDo(){
				memberField = this.local;
			}
		};
		new InnerClass(localField);
	}

	private int fromOther() {
	    return 20;
    }
}