「ポリモーフィズム」しよう!
前ページで説明したように、スーパークラスの参照を通してメソッドを呼び出しても、そのメソッドがオーバーライドされていたら、オーバーライドしたメソッドが呼び出されます。
この機能を使うと「ポリモーフィズム」という面白い機能を使うことができます。
まずは具体例を見てみましょう。
/**
* スーパークラス兼、インスタンス作成クラス。
*/
class PolySuper
{
/**
* サブクラスのインスタンスを作って、その参照を返します。
*/
static PolySuper getInstance( int number )
{
// 渡された番号によって作るインスタンスを変えます。
if( number == 1 )
{
return new PolySub1();
}
else if( number == 2 )
{
return new PolySub2();
}
else if( number == 3 )
{
return new PolySub3();
}
else
{
return null;
}
}
/**
* 自クラスの名前を出力するメソッドです。
*/
void printMyName()
{
System.out.println( "PolySuper" );
}
}
/**
* PolySuperクラスから継承したサブクラス x 3。
*/
class PolySub1 extends PolySuper
{
void printMyName()
{
System.out.println( "PolySub1" );
}
}
class PolySub2 extends PolySuper
{
void printMyName()
{
System.out.println( "PolySub2" );
}
}
class PolySub3 extends PolySuper
{
void printMyName()
{
System.out.println( "PolySub3" );
}
}
/**
* 実行用クラス。このクラスを実行してください。
*/
class PolyRunner
{
public static void main( String[] args )
{
// PolySuperクラスのstaticメソッドを使って
// インスタンスを取得します。
PolySuper refSuper = PolySuper.getInstance( 1 );
// printMyName()メソッドを呼び出します。
refSuper.printMyName();
// 出力結果:
// PolySub1
// PolySuperクラスのstaticメソッドを使って
// インスタンスを取得します。
refSuper = PolySuper.getInstance( 3 );
// printMyName()メソッドを呼び出します。
refSuper.printMyName();
// 出力結果:
// PolySub3
}
}
// PolyRunner.java /** * スーパークラス兼、インスタンス作成クラス。 */ class PolySuper { /** * サブクラスのインスタンスを作って、その参照を返します。 */ static PolySuper getInstance( int number ) { // 渡された番号によって作るインスタンスを変えます。 if( number == 1 ) { return new PolySub1(); } else if( number == 2 ) { return new PolySub2(); } else if( number == 3 ) { return new PolySub3(); } else { return null; } } /** * 自クラスの名前を出力するメソッドです。 */ void printMyName() { System.out.println( "PolySuper" ); } } /** * PolySuperクラスから継承したサブクラス x 3。 */ class PolySub1 extends PolySuper { void printMyName() { System.out.println( "PolySub1" ); } } class PolySub2 extends PolySuper { void printMyName() { System.out.println( "PolySub2" ); } } class PolySub3 extends PolySuper { void printMyName() { System.out.println( "PolySub3" ); } } /** * 実行用クラス。このクラスを実行してください。 */ class PolyRunner { public static void main( String[] args ) { // PolySuperクラスのstaticメソッドを使って // インスタンスを取得します。 PolySuper refSuper = PolySuper.getInstance( 1 ); // printMyName()メソッドを呼び出します。 refSuper.printMyName(); // 出力結果: // PolySub1 // PolySuperクラスのstaticメソッドを使って // インスタンスを取得します。 refSuper = PolySuper.getInstance( 3 ); // printMyName()メソッドを呼び出します。 refSuper.printMyName(); // 出力結果: // PolySub3 } }
まずPolySuperクラスから見てみましょう。
* スーパークラス兼、インスタンス作成クラス。
*/
class PolySuper
{
/**
* サブクラスのインスタンスを作って、その参照を返します。
*/
static PolySuper getInstance( int number )
{
// 渡された番号によって作るインスタンスを変えます。
if( number == 1 )
{
return new PolySub1();
}
else if( number == 2 )
{
return new PolySub2();
}
else if( number == 3 )
{
return new PolySub3();
}
else
{
return null;
}
}
/**
* 自クラスの名前を出力するメソッドです。
*/
void printMyName()
{
System.out.println( "PolySuper" );
}
}
/** * スーパークラス兼、インスタンス作成クラス。 */ class PolySuper { /** * サブクラスのインスタンスを作って、その参照を返します。 */ static PolySuper getInstance( int number ) { // 渡された番号によって作るインスタンスを変えます。 if( number == 1 ) { return new PolySub1(); } else if( number == 2 ) { return new PolySub2(); } else if( number == 3 ) { return new PolySub3(); } else { return null; } } /** * 自クラスの名前を出力するメソッドです。 */ void printMyName() { System.out.println( "PolySuper" ); } }
このクラスはこれまでのスーパークラスと同じようなクラスです。printMyName()メソッドを持っていて、このメソッドがサブクラスでオーバーライドされる予定です。
1つだけ違うのは、getInstance()メソッドというstaticメソッドを持っていて、この中でサブクラスのインスタンスを作っているという点です。
そのサブクラスは、PolySub1、PolySub2、PolySub3の3クラスになります。
* PolySuperクラスから継承したサブクラス x 3。
*/
class PolySub1 extends PolySuper
{
void printMyName()
{
System.out.println( "PolySub1" );
}
}
class PolySub2 extends PolySuper
{
void printMyName()
{
System.out.println( "PolySub2" );
}
}
class PolySub3 extends PolySuper
{
void printMyName()
{
System.out.println( "PolySub3" );
}
}
/** * PolySuperクラスから継承したサブクラス x 3。 */ class PolySub1 extends PolySuper { void printMyName() { System.out.println( "PolySub1" ); } } class PolySub2 extends PolySuper { void printMyName() { System.out.println( "PolySub2" ); } } class PolySub3 extends PolySuper { void printMyName() { System.out.println( "PolySub3" ); } }
この3クラスはすべてPolySuperクラスのサブクラスで、printMyName()メソッドをオーバーライドしています。これはこれまで見てきたサブクラスと同じですね。
今回の例は、スーパークラスとサブクラスの関係という点ではこれまでとほぼ同じです。
違うのは、スーパークラスにgetInstance()メソッドがあることと、サブクラスが3つもあるという点くらいです。
それよりも、使う側、インスタンスを作る箇所がこれまでと大きく異なります。
// インスタンスを取得します。
PolySuper refSuper = PolySuper.getInstance( 1 );
// printMyName()メソッドを呼び出します。
refSuper.printMyName();
// 出力結果:
// PolySub1
// PolySuperクラスのstaticメソッドを使って
// インスタンスを取得します。
refSuper = PolySuper.getInstance( 3 );
// printMyName()メソッドを呼び出します。
refSuper.printMyName();
// 出力結果:
// PolySub3
// PolySuperクラスのstaticメソッドを使って // インスタンスを取得します。 PolySuper refSuper = PolySuper.getInstance( 1 ); // printMyName()メソッドを呼び出します。 refSuper.printMyName(); // 出力結果: // PolySub1 // PolySuperクラスのstaticメソッドを使って // インスタンスを取得します。 refSuper = PolySuper.getInstance( 3 ); // printMyName()メソッドを呼び出します。 refSuper.printMyName(); // 出力結果: // PolySub3
これまではnewを使ってインスタンスを作っていましたが、今回はPolySuperクラスのgetInstance()メソッドを呼び出しています。参照を受け取っている箇所は同じですから、このgetInstance()メソッドがインスタンスを作成しているということです(getInstance()メソッドはstaticメソッドですからインスタンスを作らなくても呼び出せます)。
ではそのgetInstance()メソッドでは何をしているのか、もう一度ちゃんと見てみましょう。
* サブクラスのインスタンスを作って、その参照を返します。
*/
static PolySuper getInstance( int number )
{
// 渡された番号によって作るインスタンスを変えます。
if( number == 1 )
{
return new PolySub1();
}
else if( number == 2 )
{
return new PolySub2();
}
else if( number == 3 )
{
return new PolySub3();
}
else
{
return null;
}
}
/** * サブクラスのインスタンスを作って、その参照を返します。 */ static PolySuper getInstance( int number ) { // 渡された番号によって作るインスタンスを変えます。 if( number == 1 ) { return new PolySub1(); } else if( number == 2 ) { return new PolySub2(); } else if( number == 3 ) { return new PolySub3(); } else { return null; } }
getInstance()メソッドは、引数で渡された番号によって作るインスタンスを変えます。
1が渡されたらPolySub1。
2が渡されたらPolySub2。
3が渡されたらPolySub3。
渡された番号によって作るインスタンスを変えて、作ったインスタンスへの参照を返します。
ここがポイントです。getInstance()メソッドの戻り値の型はPolySuperクラス、つまりPolySub1・PolySub2・PolySub3のスーパークラスです。サブクラスの参照はスーパークラスの参照型へとアップキャストされるので、そのまま返すことができます。
まず最初に、getInstance()メソッドに1を渡しています。
するとPolySub1クラスのインスタンスが作られ、その参照が返されます。
// インスタンスを取得します。
PolySuper refSuper = PolySuper.getInstance( 1 );
// printMyName()メソッドを呼び出します。
refSuper.printMyName();
// 出力結果:
// PolySub1
// PolySuperクラスのstaticメソッドを使って // インスタンスを取得します。 PolySuper refSuper = PolySuper.getInstance( 1 ); // printMyName()メソッドを呼び出します。 refSuper.printMyName(); // 出力結果: // PolySub1
refSuper変数には今作られた「PolySub1クラスのインスタンス」への参照が入れられます。
そのため、printMyName()メソッドを呼び出すと「PolySub1クラスのprintMyName()メソッド」が呼び出されます。
refSuper変数はPolySuperクラスの参照型ですが、参照先のインスタンスはPolySub1クラスで、その中でprintMyName()メソッドをオーバーライドしているのでそのメソッドが呼び出されるわけです。
今度は、getInstance()メソッドに3を渡します。するとPolySub3クラスのインスタンスが作られ、その参照が返されます。
// インスタンスを取得します。
refSuper = PolySuper.getInstance( 3 );
// printMyName()メソッドを呼び出します。
refSuper.printMyName();
// 出力結果:
// PolySub3
// PolySuperクラスのstaticメソッドを使って // インスタンスを取得します。 refSuper = PolySuper.getInstance( 3 ); // printMyName()メソッドを呼び出します。 refSuper.printMyName(); // 出力結果: // PolySub3
refSuper変数には今作られた「PolySub3クラスのインスタンス」への参照が入れられます。
そのため、printMyName()メソッドを呼び出すと「PolySub3クラスのprintMyName()メソッド」が呼び出されます。
今度の参照先インスタンスはPolySub3クラスなので、そのprintMyName()メソッドが呼び出されるわけです。
このようなことが、これまで説明してきた「オーバーライド」と「アップキャスト」で行われるわけです。
さて、ここで参照を取得してprintMyName()メソッドを呼び出している箇所を並べてみましょう。
refSuper.printMyName();
// PolySub1
refSuper = PolySuper.getInstance( 3 );
refSuper.printMyName();
// PolySub3
PolySuper refSuper = PolySuper.getInstance( 1 ); refSuper.printMyName(); // PolySub1 refSuper = PolySuper.getInstance( 3 ); refSuper.printMyName(); // PolySub3
ここで注目して欲しいのは、printMyName()メソッドを呼び出している箇所です。
どちらも「refSuper.printMyName();」としています。呼び出し方はまったく一緒です。
なのに、出力結果が異なります。
これは、実際に呼び出されているメソッドが、上はPolySub1クラスのprintMyName()メソッドで、下はPolySub3クラスのprintMyName()メソッドだからです。
この「呼び出しているメソッドが一見同じなのに処理結果が変わる」という機能を「ポリモーフィズム」と言います。
同じことをしているのに、参照先のインスタンスによって実際に呼び出されるメソッドが変わり、結果も変わる……この不思議な機能は「ポリモーフィズム」と呼ばれ、オブジェクト指向プログラミングでもとても重要な機能です。
一見なんか滅茶苦茶な機能のように見えますが、でも基本的な原理は「オーバーライド」と「アップキャスト」の組み合わせ、ということはしっかり憶えておいてください。この2つの組み合わせでポリモーフィズムは実現するわけです。