5

次のコード セグメントを検討してください。

class A{ /* assume static and non static block are here */ }
class B extends A{ /* assume static and non static block are here */ }

メインメソッドでは、

 new B();

したがって、初期化の順序は次のようになります。

  1. クラス A の静的メンバーの初期化
  2. クラス B の静的メンバーの初期化
  3. クラス A の非静的メンバーの初期化
  4. 次に、コンストラクター A 内でコードを実行します
  5. クラス B の非静的メンバーの初期化
  6. 次に、コンストラクター B 内でコードを実行します

このコード セグメントを見てみましょう。

class A{
    A(){
        this.m(); //line 1
    }

    void m(){
        System.out.println("A.m()");
    }
  }

  class B extends A{
     void m(){
        System.out.println("B.m()");
    }
  }

メインメソッドでは、

 new B();

コンストラクター A のコードが実行されているとき、非静的メンバーはクラス B に対してまだ初期化されていないため (前述の順序に従って)、クラス A のメソッド m しか表示されません。ただし、結果は「Bm()」です。(サブクラスのメソッドが実行されました)誰かが私が言及した順序を考慮して、ここで何が起こっているのか(メソッドのオーバーライド)を説明できますか?

4

2 に答える 2

8

コンストラクター A のコードが実行されているとき、非静的メンバーはクラス B に対してまだ初期化されていないため (前述の順序に従って)、クラス A のメソッド m しか表示されません。

メソッドは、初期化される「非静的メンバー」の一部であると想定しています。そうではありません。実際には、コンストラクターが終了したときに初期化されるフィールドの問題です。BA

Java でオブジェクトが作成されるとすぐに、そのタイプが設定され、変更されることはありません。すべてのフィールドに十分なスペースが割り当てられますが、フィールドは実際には継承階層の最上位から順に初期化されます。

そうです、オーバーライドされたメソッドをコンストラクターから呼び出すと、使用したいフィールドの一部が初期化されていないコンテキストで実行されるため、可能であればそれを避ける必要があります。

于 2013-08-12T15:27:36.383 に答える
3

メソッドのオーバーライドは、派生クラスが初期化されているかどうかに関係なく発生します。

これが、イニシャライザで仮想メソッドを呼び出さないようにする必要がある理由です。

于 2013-08-12T15:27:08.530 に答える