このような質問で、SCJP 試験は、隠蔽と呼ばれるものに関する知識を評価しています。審査官は、プログラムの動作がポリモーフィズムのみに依存していると信じ込ませるために、故意に物事を複雑にしました。
addFive()メソッドを削除して、物事をもう少し明確にしてみましょう。
class Foo {
public int a = 3;
}
class Bar extends Foo {
public int a = 8;
}
public class TestClass {
public static void main(String[]args) {
Foo f = new Bar();
System.out.println(f.a);
}
}
これで、物事は少し混乱しなくなりました。このメソッドは、実行時に type のオブジェクトに割り当てられるmaintype の変数を宣言します。これは から継承されているため可能です。次に、プログラムは type の変数のpublic フィールドを参照します。FooBarBarFooaFoo
ここでの誤りは、オーバーライドと呼ばれる同じ種類の概念がクラス フィールドに適用されると信じることです。しかし、フィールドにはそのような概念はありません。クラスのパブリック フィールドは、aクラスのパブリック フィールドをオーバーライドBarするのではなく、非表示と呼ばれることを行います。名前が示すように、クラスのスコープ内で、がのフィールドとは関係のない 自身のフィールドを参照することを意味します。( JLS 8.4.8 - 継承、オーバーライド、非表示)aFooBaraBarFoo
それで、私たちが書いているとき、私たちはf.aどちらaを参照していますか? フィールドの解決は、オブジェクトの宣言型を使用してコンパイル時aに行われることを思い出してください。結果として、プログラムは「3」を出力します。fFoo
では、クラスにaddFive()メソッドを追加して、試験問題のようFooにクラスでオーバーライドしてみましょう。Barここではポリモーフィズムが適用されるため、呼び出しf.addFive()はコンパイル時ではなく object の実行時の型 (つまり ) を使用して解決されるfため、 Bar'b' と出力されます。
しかし、まだ理解しておかなければならないことがありaます。5 単位増加したフィールド が、値 '3' に固執するのはなぜでしょうか? ここで隠れて遊んでいます。Barこれは呼び出されるclass のメソッドであり、classBarでは、everyがの public フィールドaを参照するため、これは実際にインクリメントされるフィールドです。BaraBar
1) ここで、補助的な質問が 1 つあります。メソッドからBarのパブリック フィールドにアクセスするにはどうすればよいでしょうか。次のようなものでそれを行うことができます:amain
System.out.println( ((Bar)f).a );
これにより、コンパイラは as のフィールドのフィールド メンバーを強制的にa解決fしBarますa。
これにより、この例では「b 13」が出力されます。
2) さらに別の質問:のフィールドではなく、そのスーパークラスの同名フィールドを参照するために、クラスのメソッドに隠れて回避するにはどうすればよいでしょうか? フィールド参照の前にキーワードを追加するだけでうまくいきます。addFive()BarBarasuper
public void addFive() {
super.a += 5;
System.out.print("b ");
}
これにより、この例では「b 8」が出力されます。
最初のステートメントに注意してください
public void addFive() {
this.a += 5;
System.out.print("b ");
}
に洗練することができます
public void addFive() {
a += 5;
System.out.print("b ");
}
コンパイラが field を解決するときa、メソッド内から最も近い外側のスコープを調べ始め、クラス インスタンスaddFive()を見つけて、明示的に使用する必要がなくなるためです。Barthis
でもまあ、this受験生がこの試験問題を解く手がかりだったのかもしれませんね!