このような質問をすると、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);
}
}
これで少し混乱が少なくなりました。main
メソッドは、タイプFoo
の変数を宣言します。実行時にタイプBar
のオブジェクトが割り当てられます。これは、Bar
がFoo
から継承されているため可能です。このプログラムは、Foo
という変数のパブリックフィールドa
を参照します。
をオーバーライドすると同じ種類の概念がクラスフィールドに適用されると考えられます。しかし、フィールドには、このような概念はありません:公共の場クラスBar
のa
は、クラスFoo
の公共分野a
ないオーバーライドですが、それはを隠しと呼ばれているものを行います。名前が意味するように、それはクラスBar
の範囲で、a
はFoo
のものとは関係のないBar
の自身のフィールドを参照することを意味します。 (JLS 8.4.8 - Inheritance, Overriding, and Hiding)
f.a
と書いているので、a
を参照していますか?フィールドa
の解像度は、Foo
というオブジェクトf
の宣言型を使用して、コンパイル時にで行われることを思い出してください。結果として、プログラムは「3」を印刷する。
今度は、Foo
にaddFive()
メソッドを追加し、試験の質問と同様にクラスBar
でオーバーライドします。ここではポリモフィズムが適用されるため、f.addFive()
コールはコンパイル時ではなく、オブジェクトf
の実行時タイプBar
を使用して解決され、したがって 'b'が出力されます。
しかし、まだ理解しておかなければならないことがあります。a
というフィールドが5単位増分されたままの理由は、依然として値 '3'に固執していますか?ここでを隠してが遊んでいます。これは呼び出されるクラスBar
のメソッドであり、クラスBar
では、a
はすべてBar
の公開フィールドa
を指しているため、実際にはBar
フィールドがインクリメントされます。
1)さて、1つの子会社の質問:はどのように我々はmain
方法からBar
の公開フィールドa
アクセスすることができましたか?
Bar
さんa
フィールドとしてf
のフィールドメンバa
を解決するために、コンパイラを強制 System.out.println(((Bar)f).a);
:私たちのようなものであることを行うことができます。
この例では、で「b 13」と表示されます。
2)さらに別の質問:はどのように我々はないBar
のa
フィールドではなく、そのスーパーeponimousフィールドを参照するために、クラスBar
のaddFive()
方法でを隠しを回避することができますか?ただ、フィールド参照の前にsuper
キーワードを追加するとトリックん:これは私たちの例で「B 8」
public void addFive() {
super.a += 5;
System.out.print("b ");
}
印刷します。コンパイラは、フィールドa
を解決したとき、それは内から最も近い囲みスコープで見て開始しますので、最初の文の
public void addFive() {
this.a += 5;
System.out.print("b ");
}
が
に洗練することができることを
注意メソッドaddFive()
を検索し、Bar
クラスインスタンスを見つけて、明示的にthis
を使用する必要がなくなります。
しかし、よく、this
はおそらくこの試験問題を解決するための受験者の手掛かりでした!
これはSCJPに関する質問です。 –
うん@PrakharMohanも同じように登場しましたか?私はまだありません::) –