ここで重要なのは、内部クラスが外部クラスのメンバーにアクセスする方法を理解することです。private
そして、メンバーの場合、これらのメンバーへのアクセスはどのように修飾されますかnon-private
。(注:static
質問はそれについてのみであるため、ここでは非内部クラスについて説明します)。
内部クラスは、囲んでいるインスタンスへの参照を格納します。
内部クラスは、外側のインスタンスへの参照をフィールドとして格納します。フィールドの名前はthis$0
. 外側のインスタンスは、常に内部クラス オブジェクトにバインドされます。外側のクラスの内部から内部クラスのオブジェクトを作成すると、this$0
それらの参照値はすべて同じままですが、this
参照は異なります。
内部クラスの構文をthis$0
使用してフィールドにアクセスします。Outer.this
たとえば、次のコードを検討してください。
class Outer {
public Outer() { }
public void createInnerInstance() {
Inner obj1 = new Inner();
Inner obj2 = new Inner();
}
private class Inner {
public Inner() {
System.out.println(Outer.this);
System.out.println(this);
}
}
}
public static void main(String[] args) {
new Outer().createInnerInstance();
}
このコードを実行すると、次のような出力が得られます。
Outer@135fbaa4
Outer$Inner@45ee12a7
Outer@135fbaa4
Outer$Inner@330bedb4
1番目と 3番目の参照は同じですが、2番目と 4番目の参照は異なることに注意してください。
this$0
外部クラスのメンバーは、参照を使用して内部クラスでアクセスできます。
フィールドまたは内部クラスから外部クラスの他のメンバーにアクセスすると、アクセス式は自動的に修飾されますthis$0
。this$0
参照を使用してメンバー アクセスを明示的に修飾しOuterClass.this
ます。value
したがって、外側のクラスのフィールドを考慮しpublic
、次にshowValue()
内側のクラスのメソッドで次のようにします。
public void showValue() {
System.out.println(TestInnerClass.this.value);
System.out.println(value);
}
最初の 2 つの print ステートメントは同等です。それらは同じバイト コードにコンパイルされます。
public void showValue();
Code:
0: getstatic #3 // Field java/lang/System.out:Ljava/
o/PrintStream;
3: aload_0
4: getfield #1 // Field this$0:LTestInnerClass;
7: getfield #4 // Field TestInnerClass.value:Ljava/lang/Stri
g;
10: invokevirtual #5 // Method java/io/PrintStream.printl
:(Ljava/lang/String;)V
13: getstatic #3 // Field java/lang/System.out:Ljava/
o/PrintStream;
16: aload_0
17: getfield #1 // Field this$0:LTestInnerClass;
20: getfield #4 // Field TestInnerClass.value:Ljava/lang/Stri
g;
23: invokevirtual #5 // Method java/io/PrintStream.printl
:(Ljava/lang/String;)V
26: return
を使用して外部クラスのメンバーに明示的にアクセスすることはできませんthis
。
内部クラスでフィールドまたはメソッド アクセス式を明示的に修飾しようとするthis
と、コンパイラ エラーが発生します。
public void showValue() {
System.out.println(this.value); // this won't compile
}
value
は内部クラス自体のフィールドではないため、上記の print ステートメントはコンパイルされません。それは外部クラスのフィールドです。this
外側のインスタンスではなく、内側のクラス インスタンスを参照します。
内部クラスが外部クラスを拡張すると、ストーリーが変わります。
内部クラスが外部クラスを拡張するとき、物事がおかしくなり始めます。その場合、フィールドまたはメソッドへのアクセスを で修飾するとthis
、非プライベート メンバーに対して有効になるためです。メンバーは継承されないため、メンバーprivate
の場合はまだ有効ではありません。private
継承された内部クラスの場合、外部クラスのメンバーへの直接アクセスは で修飾されthis
ます。つまり、それらは内部クラス メンバーとしてアクセスされます。でアクセスを明示的に修飾している間Outer.this
、囲んでいるインスタンスのフィールドを参照します - this$0
.
value
フィールドが次のように宣言されていることを考慮してくださいpublic
:
public void showValue() {
System.out.println(value); // inner class instance field
System.out.println(this.value); // inner class instance field
System.out.println(Outer.this.value); // enclosing instance field
}
最初の 2 つの print ステートメントはvalue
内部クラス インスタンスのフィールドを出力し、3 番目の print ステートメントは外側のインスタンスのvalue
フィールドを出力します。混乱している?
外部クラスの内部から内部クラスの複数のインスタンスを作成すると、それらは同じthis$0
参照を持つことになると言ったことを思い出してください。
外部クラスのインスタンスを作成するとします。
new Outer("rohit").callShowValue();
メソッドでcallShowValue()
、内部クラスのインスタンスを作成します。
new Inner("rj").showValue();
ここで、showValue()
メソッドの出力は次のようになります。
rj
rj
rohit
this.value
は とは異なることに気付くでしょうOuter.this.value
。
value
フィールドを作成するとどうなりますかprivate
:
さて、外部クラス field を作成するとprivate
、もちろん を使用してアクセスすることはできませんthis.value;
。したがって、2 番目の print ステートメントはコンパイルされません。
その場合のフィールドへの直接アクセスは、this$0
この時間で修飾されます。ここで、フィールドvalue
private を変更し、showValue()
メソッドを次のように変更します。
public void showValue() {
System.out.println(value); // enclosing instance field
System.out.println(this.value); // compiler error
System.out.println(Outer.this.value); // enclosing instance field
}
ここに問題があります。最初の print ステートメントは、フィールドがまたはであるかどうかに基づいて、またはで修飾value
されます。this
this$0
public
private
あなたの具体的な問題に来て:
コードでは、value
フィールドとgetValue()
メソッドの両方がprivate
であるため、メソッドは次のようになりshowValue()
ます。
public void showValue() {
System.out.println(getValue());
System.out.println(value);
}
と同じです:
public void showValue() {
System.out.println(TestInnerClass.this.getValue());
System.out.println(TestInnerClass.this.value);
}
これは、インスタンスを囲むフィールドとメソッドにアクセスしています。そして、フィールドはまだInitial Valueです。そのため、出力は次のようになります。
初期値
初期値