2012-08-15 5 views
15

私のコードを必要がある:Javaのコードスニペットの出力説明は

class Foo { 
    public int a=3; 
    public void addFive() { 
    a+=5; 
    System.out.print("f "); 
    } 
} 

class Bar extends Foo { 
    public int a=8; 
    public void addFive() { 
    this.a += 5; 
    System.out.print("b "); 
    } 
} 

public class TestClass { 
    public static void main(String[]args) { 
    Foo f = new Bar(); 
    f.addFive(); 
    System.out.println(f.a); 
    } 
} 

出力:

b 3 

なぜこの質問に "B 3" およびない「B 13の出力はある、私に説明してください"メソッドがオーバーライドされているので?

+0

これはSCJPに関する質問です。 –

+0

うん@PrakharMohanも同じように登場しましたか?私はまだありません::) –

答えて

14

あなたは、したがって、あなたは、実際には2つのaの変数を持って、Javaで変数を上書きすることはできません。一方、addFive()メソッドは多型であるため、Bar.a(がFooの静的型であるにもかかわらず、Bar.addFive()が呼び出されます)が変更されます。

最終的には、f.aにアクセスし、この参照は、fの既知のタイプ(Foo)を使用してコンパイル時に解決されます。したがって、Foo.aは決して触られませんでした。

Javaの最終的な変数は、ではありません。は公開されます。

+4

'GridBagConstraints'などのオブジェクトがある場合を除いて。しかし、初心者のために、**決して**適切なアドバイスです:) –

18

FタイプFooの基準であり、変数は多型ではないので、f.a、それを検証する方法3

あるFooから変数を指しますか?また彼らに


にアクセスするためのメンバ変数privateおよび使用アクセサを作る:あなたはFooからa変数を削除することができ、これをテストするには

、それは時間の誤差

注意をコンパイルあなたを与えるだろう

+10

この答えを少し拡張するために、これは変数に直接アクセスする代わりにゲッターを使用する方が安全である理由の1つです。 –

+0

@DaveNewtonゲッターについて教えてください。私は以前これを聞いていない。 –

+2

この問題は、Javaで一般的なプログラミング方法を使用すると静かに回避できます。変数はプライベートである必要があります(独自のクラスだけが使用できます)。その後、上記のように、gettersとsettersメソッドを使用してアクセス/変更します。 – axcdnt

1

あなたはf.aを行っているので、Fooクラスからaの値を取得します。たとえば値getA()を取得するメソッドを呼び出した場合は、クラスBarの値を取得していました。

11

このような質問をすると、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のオブジェクトが割り当てられます。これは、BarFooから継承されているため可能です。このプログラムは、Fooという変数のパブリックフィールドaを参照します。

をオーバーライドすると同じ種類の概念がクラスフィールドに適用されると考えられます。しかし、フィールドには、このような概念はありません:公共の場クラスBaraは、クラスFooの公共分野aないオーバーライドですが、それはを隠しと呼ばれているものを行います。名前が意味するように、それはクラスBarの範囲で、aFooのものとは関係のないBarの自身のフィールドを参照することを意味します。 (JLS 8.4.8 - Inheritance, Overriding, and Hiding

f.aと書いているので、aを参照していますか?フィールドaの解像度は、Fooというオブジェクトfの宣言型を使用して、コンパイル時にで行われることを思い出してください。結果として、プログラムは「3」を印刷する。

今度は、FooaddFive()メソッドを追加し、試験の質問と同様にクラス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)さらに別の質問:はどのように我々はないBaraフィールドではなく、そのスーパーeponimousフィールドを参照するために、クラスBaraddFive()方法でを隠しを回避することができますか?ただ、フィールド参照の前に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はおそらくこの試験問題を解決するための受験者の手掛かりでした!

+0

素敵な説明アレックス – Pratswinz

関連する問題