-1

コードは次のようになります。

class Base {
    int x = 10;

    public Base() {
        this.printMessage();
        x = 20;
    }

    public void printMessage() {
        System.out.println("Base.x = " + x);
    }
}

class Sub extends Base {
    int x = 30;

    public Sub() {
        this.printMessage();
        x = 40;
    }

    public void printMessage() {
        System.out.println("Sub.x = " + x);
    }
}

public class DispatchTest {
    public static void main(String[] args) {
        Base b = new Sub();
        System.out.println(b.x);
    }
}

結果は次のとおりです。

Sub.x = 0
Sub.x = 30
20

このコードがどのように実行されるか教えてください。クラス Base のコンストラクターが実行されないのはなぜですか?

4

4 に答える 4

2

新しいSubオブジェクト インスタンスを作成したためです。クラスSubにはprintMessage()オーバーライドされたメソッドがあります。これは、Base.printMethod()が実行されていないことを意味します。

Baseクラスのコンストラクターは実行されますが、クラスからメソッドがthis.printMessage()実行されます。printMessageSub

のコンストラクターが呼び出された直後に、Subコンストラクターが呼び出されていますBase。これまでに (in ) が設定されていSub.x = 0ないため、印刷されます。その後、値が割り当てられます。xSubx

コンストラクターが完了するBaseと、残りのSubコンストラクターが実行されます。Subのメソッドを再度呼び出すと表示されますprintMessageが、今回は値xに値があり、 と表示されますSub.x = 30

20から来ていSystem.out.println(b.x);ます。

最初の呼び出しで値xが割り当てられないのはなぜでしょうか? printMessageあなたもxあなたのSubクラスにいるので、クラスxからのBaseは見えません!

于 2013-08-10T13:16:19.410 に答える
1

SuperClass コンストラクターは常に呼び出されますが、「オーバーライドされたメンバー変数にアクセスすると、ポリモーフィックな動作が見られません」。

  Base b = new Sub();
  System.out.println(b.x);

x(サブクラスとスーパークラスの両方に存在する)にアクセスすると、実際には値を決定する参照変数の型になります。

注:この動作は、オーバーライドされたメソッドでは異なります。この場合、実際には、参照変数の型ではなく、呼び出されるメソッドを決定するのはオブジェクトの型です。

于 2013-08-10T13:19:33.953 に答える
1

コンストラクター

    public Sub() {
        this.printMessage();
        x = 40;
    }

と同等です

public Sub() {
        super();
        this.printMessage();
        x = 40;
}

だから作成するときは

Base b = new Sub();

Baseのコンストラクターが実行され、続いて のコンストラクターが実行されSubます。JLS 8.8.7 を参照してください

コンストラクター本体の最初のステートメントは、同じクラスまたは直接のスーパークラスの別のコンストラクターの明示的な呼び出しである可能性があります


Baseのコンストラクターが呼び出しており、printMessage()これはによってオーバーライドされSubます。Baseのコンストラクタから呼び出されると、まだ初期化されていませんprintMessage()。これはアンチパターンなので出力されます(はまだ初期化されていないため、 int のデフォルト値は です)xSubSub.x = 0x0


Base のコンストラクターが終了すると、Subのコンストラクターが呼び出され、xが初期化される30理由は何ですか?

なぜなら

class Sub extends Base {
    int x = 30;

    public Sub() {
        this.printMessage();
        x = 40;
    }
    ....

本質的には

class Sub extends Base {
    int x;

    public Sub() {
        {
            x=30;
        }
        this.printMessage();
        x = 40;
    }
    ....

したがって、今回printMessage()は印刷されますSub.x = 30


フィールドオーバーライド20されないため、最終的に出力されます。

于 2013-08-10T13:25:06.770 に答える
0

子クラス オブジェクトを作成するたびに、次の一連のイベントが自動的に実行されます。

ステップ 1. 親から子へのインスタンス メンバーの識別とデフォルト値への初期化。

最初のステップの後

基本インスタンス変数は int x=0;
サブインスタンス変数は int x=0;

Step 2.親クラスのみでのインスタンス変数代入とインスタンスブロックの実行

二段目以降

基本クラスのインスタンス変数は int x= 10;
サブクラスのインスタンス変数は int x = 0;

ステップ 3.親クラスのコンストラクターの実行。

三段目以降

ここに「printMessage()」呼び出しがあります。これは子クラス Sub でオーバーライドされるため、Sub クラス メソッドが実行され、Sub クラスの変数 x 値が出力されます。これは現在 0 のみとして割り当てられています。
したがって、出力は「Sub.x = 0」になりました。基本クラス int x = 20; サブクラス int x = 0;

ステップ 4.子クラスのインスタンス変数とインスタンス ブロックの実行。

4段目以降

基本クラス int x=20; サブクラス int x=30;

ステップ 5.子コンストラクターの実行。

5段目以降。

サブクラスコンストラクターでは、「printMessage()」メソッドの呼び出しがあります。そのため、実行して出力を出力します。
したがって、出力は「Sub.x = 30」になります。
メソッド呼び出しの後、割り当てがあります。
だから今基本クラスint x = 20; サブクラス int x=40;

今のところ、Sub クラス コンストラクターは正常に作成されています。
これで、型参照「Base」で変数 x の print ステートメントが作成されました。したがって、「Base」クラスの変数 x が出力として出力されます。

したがって、アウトプットは「20」です。

于 2013-08-10T13:50:41.963 に答える