オーバーライドされたメソッドを呼び出す
前ページでは、アップキャストをすることで「使えるフィールド・メソッドがスーパークラスのものに限られる」ということを説明しました。
この状態で、スーパークラスの「オーバーライドされたメソッド」を呼び出すと、面白いことが起きます。
/**
* 普通のクラス。
* メソッド1つ持ちます。
* (HasOneMethodSuperクラスと全く同じです)
*/
class HasOneMethodSuper4
{
/**
* 自クラスの名前を出力するメソッドです。
*/
void printMyName()
{
System.out.println( "HasOneMethodSuper4" );
}
}
/**
* HasOneMethodSuper4クラスから継承した、サブクラス。
* メソッドを追加しています。
* (OverridedSubクラスと全く同じです)
*/
class OverridedSub4 extends HasOneMethodSuper4
{
/**
* 自クラスの名前を出力するメソッドです。
* オーバーライドしています。
*/
void printMyName()
{
System.out.println( "OverridedSub4" );
}
}
/**
* 実行用クラス。このクラスを実行してください。
*/
class OverridedSub4Runner
{
public static void main( String[] args )
{
// インスタンスを1つ作ります。
// ただし、参照型変数の型はスーパークラスです。
HasOneMethodSuper4 refSuper = new OverridedSub4();
// printMyName()メソッドを呼び出します。
refSuper.printMyName();
// 出力結果:
// OverridedSub4
}
}
// OverridedSub4Runner.java /** * 普通のクラス。 * メソッド1つ持ちます。 * (HasOneMethodSuperクラスと全く同じです) */ class HasOneMethodSuper4 { /** * 自クラスの名前を出力するメソッドです。 */ void printMyName() { System.out.println( "HasOneMethodSuper4" ); } } /** * HasOneMethodSuper4クラスから継承した、サブクラス。 * メソッドを追加しています。 * (OverridedSubクラスと全く同じです) */ class OverridedSub4 extends HasOneMethodSuper4 { /** * 自クラスの名前を出力するメソッドです。 * オーバーライドしています。 */ void printMyName() { System.out.println( "OverridedSub4" ); } } /** * 実行用クラス。このクラスを実行してください。 */ class OverridedSub4Runner { public static void main( String[] args ) { // インスタンスを1つ作ります。 // ただし、参照型変数の型はスーパークラスです。 HasOneMethodSuper4 refSuper = new OverridedSub4(); // printMyName()メソッドを呼び出します。 refSuper.printMyName(); // 出力結果: // OverridedSub4 } }
このプログラムは「5.3 オーバーライドで「上書き」する」に似たプログラムです。
HasOneMethodSuper4クラスとOverridedSub4クラスはその時のものと全く同じで、クラス名が違うだけです。
継承関係も同じで、HasOneMethodSuper4クラスからOverridedSub4クラスに継承しています。HasOneMethodSuper4クラスがスーパークラス、OverridedSub4クラスとなります。
また、HasOneMethodSuper4クラスのprintMyName()メソッドをOverridedSub4クラスでオーバーライドしています。
インスタンスの作成箇所は少し違います。
参照型変数の型をスーパークラスのHasOneMethodSuper4クラスにして、アップキャストして受け取っています。
// ただし、参照型変数の型はスーパークラスです。
HasOneMethodSuper4 refSuper = new OverridedSub4();
// インスタンスを1つ作ります。 // ただし、参照型変数の型はスーパークラスです。 HasOneMethodSuper4 refSuper = new OverridedSub4();
インスタンスはOverridedSub4クラス型なので、中にHasOneMethodSuper4クラスのインスタンスも作られ、オーバーライドしているprintMyName()メソッドが結びつけられます。
このrefSuper変数の型はHasOneMethodSuper4クラスですので、HasOneMethodSuper4クラスのフィールド・メソッドのみ使用できます。
サブクラスであるOverridedSub4クラスのフィールド・メソッドは使えません。
さてでは、refSuper変数を通して、printMyName()メソッドを呼び出すと、どうなるのでしょう。
printMyName()メソッドはオーバーライドしているわけですから、スーパークラスにもサブクラスにもあります。
refSuper変数はスーパークラスの参照型変数ですから、当然スーパークラスのprintMyName()メソッドが呼び出される……と思いきや、実はサブクラスの、オーバーライドしたメソッドが呼び出されます。
refSuper.printMyName();
// 出力結果:
// OverridedSub4
// printMyName()メソッドを呼び出します。 refSuper.printMyName(); // 出力結果: // OverridedSub4
この実行結果のように、OverridedSub4クラスのprintMyName()メソッドが呼び出されています。
refSuper変数はスーパークラス・HasOneMethodSuper4クラスなのに、呼び出されたのはサブクラス・OverridedSub4クラスのprintMyName()メソッドということです。
なぜこのようになるかというと、「オーバーライドされたメソッドからオーバーライドしたメソッドへひもが付いている」からです。
「5.3 オーバーライドで「上書き」する」で説明したように、メソッドをオーバーライドすると、オーバーライドされたメソッドからオーバーライドしたメソッドへひもが付けられ、「オーバーライドしたメソッド」が呼び出されるようになります。
そのため、スーパークラスの参照型変数を通して呼び出しても、「オーバーライドしたメソッド」が呼び出されます。
refSuper変数はスーパークラスの参照型変数ですので、スーパークラスのprintMyName()メソッドが呼び出されようとするのですが、このメソッドはサブクラスでオーバーライドしているので、自動的にサブクラスのprintMyName()メソッドが呼び出されるわけです。
実は、これは「5.4 オーバーライドされたメソッドを呼び出すと?」と同じ現象です。
あの時も、スーパークラスのprintMyName()メソッドを呼び出したと思ったら、サブクラスのprintMyName()メソッドが自動的に呼び出されていました。
オーバーライドをすることで、一見スーパークラスのメソッドを呼び出したように見えて、実はサブクラスにある「オーバーライドしたメソッド」が呼び出されるようになるわけです。