おそらく質問に似ています なぜ外部Javaクラスは内部クラスのプライベートメンバーにアクセスできますか? または サブクラスでsuperキーワードを使用してスーパークラスのプライベートフィールドにアクセスできますか? 。
ただし、いくつかの違いがあります。childrenクラスは、親(および最も近いparentのみ)クラスのprivateメンバーにアクセスできます。
以下のサンプルコードを考えます。
public class T {
private int t;
class T1 {
private int t1;
public void test() {
System.out.println(t);
}
}
class T2 extends T1 {
private int t2;
public void test() {
System.out.println(t);
System.out.println(super.t1);
System.out.println(this.t2);
}
}
class T3 extends T2 {
public void test() {
System.out.println(t);
System.out.println(super.t1); // NG: t1 Compile error! Why?
System.out.println(super.t2); // OK: t2 OK
}
}
}
技術的には、 [〜#〜] jvm [〜#〜] レベルでは、[〜#〜] not [〜#〜]にアクセスできます別のクラスのprivate
メンバー—外側のクラス(_T.t
_)のメンバーでも、親クラス(_T2.t2
_)のメンバーでもありません。あなたのコードでは、コンパイラは synthetic
にアクセスするクラスのアクセサメソッドを生成するので、just like likeできます。 _T3
_クラスで無効な参照を修正した場合も同じことが起こります _ 正しい形式_super.t1
_((T1) this).t1
_を使用します。
このようなコンパイラが生成したsynthetic
アクセサメソッドを使用すると、一般的にアクセスできますanyprivate
anyのメンバー外側(最上位)T
クラスにネストされたクラス、例えば_T1
_からnew T2().t2
を使用できます。これは_private static
_メンバーにも適用されることに注意してください。
synthetic
属性は、 [〜#〜] jdk [〜#〜] リリース1.1で導入され、新しい言語であるネストされたクラスをサポートします。その時の機能Java。その時から。 [〜#〜] jls [〜#〜] は明示的にすべてのメンバーへの相互アクセスを許可します。 private
を含むトップレベルのクラス。
ただし、下位互換性のために、コンパイラーはネストされたクラスをアンラップし(例えば、_T$T1
_、_T$T2
_、_T$T3
_)、private
メンバーを変換しますaccessesを- calls生成されるsynthetic
アクセサメソッド(したがって、これらのメソッドには package private が必要です。つまり、 default 、可視性):
_class T {
private int t;
T() { // generated
super(); // new Object()
}
static synthetic int access$t(T t) { // generated
return t.t;
}
}
class T$T1 {
private int t1;
final synthetic T t; // generated
T$T1(T t) { // generated
this.t = t;
super(); // new Object()
}
static synthetic int access$t1(T$T1 t$t1) { // generated
return t$t1.t1;
}
}
class T$T2 extends T$T1 {
private int t2;
{
System.out.println(T.access$t((T) this.t)); // t
System.out.println(T$T1.access$t1((T$T1) this)); // super.t1
System.out.println(this.t2);
}
final synthetic T t; // generated
T$T2(T t) { // generated
this.t = t;
super(this.t); // new T1(t)
}
static synthetic int access$t2(T$T2 t$t2) { // generated
return t$t2.t2;
}
}
class T$T3 extends T$T2 {
{
System.out.println(T.access$t((T) this.t)); // t
System.out.println(T$T1.access$t1((T$T1) this)); // ((T1) this).t1
System.out.println(T$T2.access$t2((T$T2) this)); // super.t2
}
final synthetic T t; // generated
T$T3(T t) { // generated
this.t = t;
super(this.t); // new T2(t)
}
}
_
N.B .: synthetic
のメンバーを直接参照することは許可されていないため、ソースコードでは使用できません。 int i = T.access$t(new T());
自分。
非常に良い発見!私たちは皆、あなたのコード例をコンパイルすべきだと思っていたと思います。
残念ながら、そうではありません... [〜#〜] jls [〜#〜] は §15.11.2。 "superを使用したスーパークラスメンバーへのアクセス" (強調鉱山):
フィールドアクセス式super.fがクラスC内にあり、CのimmediateスーパークラスがクラスSであるとします。Sのfがクラスからアクセス可能な場合C(§6.6)の場合、super.fはクラスSの本体の式this.fであるかのように扱われます。そうでない場合、コンパイル時エラーが発生します。
すべてのフィールドが同じ包含クラスにあるため、アクセシビリティが提供されます。プライベートにすることもできますが、アクセス可能です。
問題は、T2
(immediateT3
のスーパークラス)でsuper.t1
をthis.t1
として扱うことが違法であるということです- t1
にフィールドT2
がありません。したがって、コンパイラエラー。