2011-09-11 20 views
3

私は三つのクラス(A、B、C)を定義:Javaの不明瞭な結果

public class A { 
    int i = 5; 
    public A() { 
     foo(); 
    } 
    public void foo() { 
     System.out.println(i); 
    } 
} 

class B extends A { 
    int i = 6; 
} 

class C extends B { 
     int i = 7; 
    public void foo() { 
     System.out.print(super.i); 
    } 
    public static void main(String[] args) { 
     C c = new C(); 
    } 
} 

期待される結果は次のとおりです。6 が、プログラムリターン:0

誰かが結果を説明することができますか? あなたの助けに感謝します。

答えて

5

クラスCオーバーライドA.foo()であり、多態性はJavaのコンストラクタでも有効です。したがって、AのコンストラクタでCのインスタンスを構築するときにfoo()を呼び出すと、実際に呼び出されるのはC.foo()です。順番に

C.foo()B.iをプリントアウトし、私たちはプリントアウトする6期待するかもしれない - しかし、インスタンス変数の初期化子をB.iが0

あり、実行の時点でだけなので、スーパークラスのコンストラクタの後 を実行しているが

は基本的には、コンストラクタの実行順序は次のとおりです。

  • 明示的this(...)チェーンに別の、連鎖コンストラクタを実行しますスーパークラスのコンストラクタに連結する場合はsuper(...)を明示的に指定するか、暗黙的にスーパークラスのパラメータのないコンストラクタに連結する場合はsuper()を暗黙的に使用します。
  • スーパークラスコンストラクタにチェーンされたコンストラクタの場合は、変数初期化子を実行します。
  • コンストラクタ本体変数初期化子を使用しないようにするためのコードと可変シャドウイング依然としてコードと同等に保ちながら、これはより明確になり書き換え

でコードを実行し、脇よう

public class A { 
    int ai; 

    public A() { 
    super(); 
    ai = 5; 
    foo(); 
    } 

    public void foo() { 
    System.out.println(ai); 
    } 
} 

class B extends A { 
    int bi; 

    public B() { 
    super(); 
    bi = 6; 
    } 
} 

class C extends B { 
    int ci; 

    public C() { 
    super(); 
    ci = 7; 
    } 

    public void foo() { 
    System.out.print(bi); 
    } 

    public static void main(String[] args) { 
    C c = new C(); 
    } 
} 

を「変数隠蔽」の部分は、すべてのフィールドを非公開にしてから始めるのではなく、私がお勧めするものです。それはコンストラクタから仮想メソッドを呼び出すという問題を残します。これはオブジェクトが完全に初期化される前にオブジェクトが動作することを期待しているために一般的には悪い考えであり、可変初期化子実行の驚くべきタイミングです。

コンストラクタから仮想メソッドを呼び出さないようにすると、変数初期化子のタイミングが無関係になります。少なくともはほぼです。

1

変数はクラスAで決して初期化されないので、prmiitive intのデフォルト変数を0にして出力します。これは、階層ツリー上のコンストラクタに対してsuperが呼び出されてもコンストラクタはiを初期化しませんこれはコンストラクタの後に起こる初期化で行われます。

+0

ないコンストラクタの後に - しかし、コンパイルされ、コンストラクタ本体の最初の部分*後*スーパークラスのコンストラクタへの呼び出し。 –

0

私はあなたが期待していることは分かりません。あなたの例はそのままでは実行されず、実行されたとしても何もしません。

この例では、「6」を返します。

public class A { 
    int i = 5; 
    public A() { 
     foo(); 
    } 
    public void foo() { 
     System.out.println(i); 
    } 
    public static void main(String[] args) { 
     C c = new C(); 
     c.foo(); 
    } 
} 

class B extends A { 
    int i = 6; 
} 

class C extends B { 
    int i = 7; 
    public void foo() { 
     System.out.print(super.i); 
    } 
} 
+0

OPのコードはコンパイルされ、私のために完全にうまく動作し、0を出力します。あなたのコードは06を出力します。コンストラクタから 'foo()'を呼び出すと、0が出力されます。コンストラクタの後に 'foo()' * 6を印刷します。 –

関連する問題