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 を見るために。