#pragma twice

KAB-studio > プログラミング > Javaのオブジェクト指向入門 > 6. 継承Q and A > 6.2 3段以上オーバーライドしたら?
 
前のページへつぎ

6.2 3段以上オーバーライドしたら?

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

オーバーライドを重ねると?

 質問:継承を3段以上行ってそれぞれでスーパークラスのメソッドをオーバーライドした場合、どのメソッドが呼ばれますか? たとえばクラスAのサブクラスBがあり、クラスBのサブクラスCがあり、クラスAのprint()メソッドをクラスB・クラスCでオーバーライドしたら、どれが呼ばれますか?
 解答:インスタンスを作ったクラスのメソッドが呼ばれます。

 継承に継承を重ね、オーバーライドにオーバーライドを重ねた場合、どのメソッドが呼ばれるのか、という点について確認しておきましょう。
 今回は3段階に継承して、それぞれのクラスでメソッドをオーバーライドします。

// SubOfSubRunner.java

/**
 * 普通のクラス。
 * メソッド1つ持ちます。
 * (HasOneMethodSuperクラスと同じです)
 */
class HasOneMethodSuper3
{
    /**
     * 自クラスの名前を出力するメソッドです。
     */
    void printMyName()
    {
        System.out.println( "HasOneMethodSuper3" );
    }
}

/**
 * HasOneMethodSuper3クラスから継承した、サブクラス。
 */
class Sub extends HasOneMethodSuper3
{
    /**
     * 自クラスの名前を出力するメソッドです。
     * オーバーライドしています。
     */
    void printMyName()
    {
        System.out.println( "Sub" );
    }
}

/**
 * Subクラスから継承した、サブクラス。
 */
class SubOfSub extends Sub
{
    /**
     * 自クラスの名前を出力するメソッドです。
     * オーバーライドしています。
     */
    void printMyName()
    {
        System.out.println( "SubOfSub" );
    }
}

/**
 * 実行用クラス。このクラスを実行してください。
 */
class SubOfSubRunner
{
    public static void main( String[] args )
    {
        // SubOfSubクラスのインスタンスを1つ作ります。
        SubOfSub ref = new SubOfSub();

        // printMyName()メソッドを呼び出します。
        ref.printMyName();
        // 出力結果:
        // SubOfSub

        // Subクラスのインスタンスを1つ作ります。
        Sub ref2 = new Sub();

        // printMyName()メソッドを呼び出します。
        ref2.printMyName();
        // 出力結果:
        // Sub
    }
}
// SubOfSubRunner.java
/**
 * 普通のクラス。
 * メソッド1つ持ちます。
 * (HasOneMethodSuperクラスと同じです)
 */
class HasOneMethodSuper3
{
	/**
	 * 自クラスの名前を出力するメソッドです。
	 */
	void printMyName()
	{
		System.out.println( "HasOneMethodSuper3" );
	}
}
/**
 * HasOneMethodSuper3クラスから継承した、サブクラス。
 */
class Sub extends HasOneMethodSuper3
{
	/**
	 * 自クラスの名前を出力するメソッドです。
	 * オーバーライドしています。
	 */
	void printMyName()
	{
		System.out.println( "Sub" );
	}
}
/**
 * Subクラスから継承した、サブクラス。
 */
class SubOfSub extends Sub
{
	/**
	 * 自クラスの名前を出力するメソッドです。
	 * オーバーライドしています。
	 */
	void printMyName()
	{
		System.out.println( "SubOfSub" );
	}
}
/**
 * 実行用クラス。このクラスを実行してください。
 */
class SubOfSubRunner
{
	public static void main( String[] args )
	{
		// SubOfSubクラスのインスタンスを1つ作ります。
		SubOfSub ref = new SubOfSub();
		// printMyName()メソッドを呼び出します。
		ref.printMyName();
		// 出力結果:
		// SubOfSub
		// Subクラスのインスタンスを1つ作ります。
		Sub ref2 = new Sub();
		// printMyName()メソッドを呼び出します。
		ref2.printMyName();
		// 出力結果:
		// Sub
	}
}

 まず、HasOneMethodSuper3クラスを用意します。

/**
 * 普通のクラス。
 * メソッド1つ持ちます。
 * (HasOneMethodSuperクラスと同じです)
 */
class HasOneMethodSuper3
{
    /**
     * 自クラスの名前を出力するメソッドです。
     */
    void printMyName()
    {
        System.out.println( "HasOneMethodSuper3" );
    }
}
/**
 * 普通のクラス。
 * メソッド1つ持ちます。
 * (HasOneMethodSuperクラスと同じです)
 */
class HasOneMethodSuper3
{
	/**
	 * 自クラスの名前を出力するメソッドです。
	 */
	void printMyName()
	{
		System.out.println( "HasOneMethodSuper3" );
	}
}

 このクラスのprintMyName()メソッドは、自クラスの名前を出力します。

 次に、このクラスのサブクラス、Subクラスを作ります。

/**
 * HasOneMethodSuper3クラスから継承した、サブクラス。
 */
class Sub extends HasOneMethodSuper3
{
    /**
     * 自クラスの名前を出力するメソッドです。
     * オーバーライドしています。
     */
    void printMyName()
    {
        System.out.println( "Sub" );
    }
}
/**
 * HasOneMethodSuper3クラスから継承した、サブクラス。
 */
class Sub extends HasOneMethodSuper3
{
	/**
	 * 自クラスの名前を出力するメソッドです。
	 * オーバーライドしています。
	 */
	void printMyName()
	{
		System.out.println( "Sub" );
	}
}

 printMyName()メソッドをオーバーライドしています。

 さらに、Subクラスのサブクラス、SubOfSubクラスも作ります。

/**
 * Subクラスから継承した、サブクラス。
 */
class SubOfSub extends Sub
{
    /**
     * 自クラスの名前を出力するメソッドです。
     * オーバーライドしています。
     */
    void printMyName()
    {
        System.out.println( "SubOfSub" );
    }
}
/**
 * Subクラスから継承した、サブクラス。
 */
class SubOfSub extends Sub
{
	/**
	 * 自クラスの名前を出力するメソッドです。
	 * オーバーライドしています。
	 */
	void printMyName()
	{
		System.out.println( "SubOfSub" );
	}
}

 このクラスでもprintMyName()メソッドをオーバーライドしています。
 つまり、printMyName()メソッドは、Subクラス、そしてSubOfSubクラスでもオーバーライドしているわけです。

 このSubOfSubクラスのインスタンスを作ってみましょう。

        // SubOfSubクラスのインスタンスを1つ作ります。
        SubOfSub ref = new SubOfSub();
		// SubOfSubクラスのインスタンスを1つ作ります。
		SubOfSub ref = new SubOfSub();

 このSubOfSubクラスのインスタンスにはSubクラスのインスタンスが入っていて、さらにその中にHasOneMethodSuper3クラスのインスタンスが入っています。
 この時、HasOneMethodSuper3クラスとSubクラスのprintMyName()メソッドはSubOfSubクラスのprintMyName()メソッドに結びつけられます

 ここでもう1つ例を見てみましょう。
 Subクラスのインスタンスを作ってみます。

        // Subクラスのインスタンスを1つ作ります。
        Sub ref2 = new Sub();
		// Subクラスのインスタンスを1つ作ります。
		Sub ref2 = new Sub();

 このSubクラスのインスタンスの中にはHasOneMethodSuper3クラスのインスタンスが入っています。
 この時、printMyName()メソッドはSubクラスのprintMyName()メソッドに結びつけられます

 つまり、どのメソッドが呼び出されるか(どのメソッドにひもが付くか)は、どのクラスのインスタンスを作ったかによる、というわけです。
 プログラムだけ見ると、なんだか「どのクラスのインスタンスを作っても、SubOfSubクラスのインスタンスが作られる」ように見えるかもしれません。自分でクラスを作ると、特にそうです。
 でも、作られるインスタンスはnewで指定したクラスのインスタンスです。そして、オーバーライドもnewで指定したクラスのメソッドになります。
 「どう動くか」をイメージするときには、プログラムそのものではなく、そこから作られるインスタンスをイメージするようにしましょう。そうすれば、どのメソッドが動くのか、イメージしやすいと思います。

6.2 3段以上オーバーライドしたら?
このページは、Java言語を用いたオブジェクト指向プログラミングのチュートリアル解説を行う「Javaのオブジェクト指向入門」の一ページです。
詳しい説明は「Javaのオブジェクト指向入門」目次をご覧ください。