#pragma twice

KAB-studio > プログラミング > Javaのオブジェクト指向入門 > 7. ポリモーフィズム!! > 7.4 ポリモーフィズム!
 
前のページへつぎ

7.4 ポリモーフィズム!

del.icio.us 登録する はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数 livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数 Yahoo!ブックマーク 詳細を表示 users RSSに登録
更新日: 2008/04/14
動作確認環境:Windows XP Professional SP2, Java SE 5

「ポリモーフィズム」しよう!

 前ページで説明したように、スーパークラスの参照を通してメソッドを呼び出しても、そのメソッドがオーバーライドされていたら、オーバーライドしたメソッドが呼び出されます。
 この機能を使うと「ポリモーフィズム」という面白い機能を使うことができます。
 まずは具体例を見てみましょう。

// 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
    }
}
// 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クラスのstaticメソッドを使って
        // インスタンスを取得します。
        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クラスのstaticメソッドを使って
        // インスタンスを取得します。
        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クラスのインスタンスが作られ、その参照が返されます

        // PolySuperクラスのstaticメソッドを使って
        // インスタンスを取得します。
        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()メソッドを呼び出している箇所を並べてみましょう。

        PolySuper refSuper = PolySuper.getInstance( 1 );
        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つの組み合わせでポリモーフィズムは実現するわけです。

7.4 ポリモーフィズム!
このページは、Java言語を用いたオブジェクト指向プログラミングのチュートリアル解説を行う「Javaのオブジェクト指向入門」の一ページです。
詳しい説明は「Javaのオブジェクト指向入門」目次をご覧ください。