-1

これはJava言語のコードです。

class A{
   A() {  print();   }
   void print() { System.out.println("A"); }
}
class B extends A{
   int i =   Math.round(3.5f);
   public static void main(String[] args){
      A a = new B();
      a.print();
   }
   void print() { System.out.println(i); }
}

0、4を出力します。しかし、コンストラクター内のスーパークラスAからサブクラスのprintメソッドを呼び出すのはなぜですか?printメソッドがオーバーライドされているように見えますが、実際には「print」メソッドがスーパークラスから呼び出されています...これは、Java認定の準備をするためのドリルです。よろしくお願いします

4

4 に答える 4

1

オブジェクトタイプ(参照タイプではない)は、実行時に使用されるオーバーライドされたメソッドを決定します/

A a = new B();
a.print();// this would always call B's print() in case of overriden methods 
于 2012-11-04T15:50:33.983 に答える
1

1 つはオブジェクトにアクセスするために使用する参照であり、もう 1 つはオブジェクトの実際の型です。これは基本的なサブタイプの多型です。

あなたのオブジェクトはタイプ B です。それはあなたが作成したものだからです (つまり new B())。ここで、タイプ A の参照を介してオブジェクトにアクセスすることになります。これは、B が A であるため可能です( B は A を拡張します)。

参照を介してメソッドprintを呼び出すと、ランタイム型システムは、参照が型 A であっても、参照が指す実際のオブジェクトは型 B であることを認識しているため、最初に Bでメソッドprintを探します。それが呼び出されたものであり、表示される出力を説明しています。

あなたの印刷メソッドは、仮想メソッドと呼ばれるものです。これは、実行時の呼び出しのターゲット オブジェクトの性質のみに基づいて、メソッドのすべての実装のどの実装が呼び出されるかを決定するのは実行時システムであることを意味します。

これで、B でオーバーライドされた実装が呼び出されます。オーバーライドされた実装は、親クラスの実装を自動的にトリガーしません。これは、コンストラクターの動作とは多少異なります (継承はできませんが、連鎖は可能です)。

したがって、これは基本的に、オーバーライドされたメソッドから親の動作にアクセスしたい場合は、スーパークラスにそれを行うように依頼する必要があることを意味します (つまり、super.print())

そのため、次の場合のようにコンストラクターを扱っていた場合

class A {
   public A() { System.out.println("A"); }
}

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

B のインスタンスを作成すると、A B の出力が表示されるはずです。これは、コンストラクターが自動的に連鎖され、B のコンストラクターが A のコンストラクターを呼び出すためです。

ただし、仮想メソッドの場合は、次のように実行を明示的にチェーンする必要があります (それが必要な場合)。

class A {
   public A() { System.out.println("A"); }
   //virtual method
   public void print(){ System.out.println("A"); }
}

class B extends {
  public B() { System.out.println("B"); }
   //virtual method overriden
   @Override
   public void print(){ 
      super.print(); //invokes A.print
      System.out.println("B"); 
   }
}

...出力 A B を見るために。

于 2012-11-04T15:53:06.137 に答える
1

printコンストラクタで呼び出さないでくださいA0のインスタンスはB明らかにまだ完全に初期化されておらず、 の値はB.i明らかにまだであるため、ここに が出力されます0

暗黙のコンストラクターB次のとおりです。

public B() {
   super(); // invokes B.print!
   this.i = Math.round(3.5f);
}

ご覧のとおり、printiは初期化される前に実行されます。それでも、 をオーバーライドprintしたため、古い印刷は実行されません。

于 2012-11-04T15:54:36.180 に答える
0

オブジェクトでメソッドを呼び出すと、スーパークラス内から呼び出された場合でも、常にオブジェクトの実際の型の実装が使用されます。

于 2012-11-04T15:49:44.517 に答える