読者です 読者をやめる 読者になる 読者になる

S_a_k_Uの日記みたいなDB

~サクゥーと呼ばないで~

継承した型によるオーバーロード

技術メモ Java

まだまだ理解してないというか把握してないことが一杯あるなぁ〜
Java 6u33


継承元のクラスOverloadTestには、init(OverloadTest)メソッドが実装されている。
サブクラスSubclassAは、init(OverloadTest)メソッドをオーバーライドしたメソッドが実装されている。
サブクラスSubclassBは、init(OverloadTest)メソッドオーバーロードしたinit(SubclassB)メソッドが実装されている。
とした時に、サブクラスSubclassBのinit(SubclassB)メソッドを呼び出す方法はあるんだろうか?
これって、ダイアモンド継承と同じような問題というか制約なんかな???
にしても、呼び出す方法があるんならいいけど、呼び出す方法がない場合はコンパイルエラーにならない理由があるのかな???


本来の形じゃなければ、ダミーの空のインターフェースDummyInterfaceを作って、サブクラスSubclassBはそれを実装して、init(DummyInterface)メソッドオーバーロード
でも結局、DummyInterface → SubclassB の型変換をせんといかんのよな。


引き続き、インターフェースでのオーバーロードも確認してみた

サンプルコード

public class OverloadTest {

    public static void main(String[] args) {
        new OverloadTest().test();
    }

    public void test() {
        System.out.println("\n■■■ OverloadTestの挙動 ■■■");
        new OverloadTest().setup();
        System.out.println("\n■■■ SubclassAの挙動 → オーバーライドしているため呼び出される ■■■");
        new SubclassA().setup();
        System.out.println("\n■■■ SubclassBの挙動 → オーバーロードしているinit(SubclassB)は呼び出れない ■■■");
        new SubclassB().setup();
    }

    /* initメソッドの呼び出し元 */
    public void setup() {
        System.out.println("==== OverloadTest型の変数でinitを呼び出します ====");
        OverloadTest test = new OverloadTest();
        init(test);
        OverloadTest testA = new SubclassA();
        init(testA);
        OverloadTest testB = new SubclassB();
        init(testB);
        System.out.println("==== SubclassA型の変数でinitを呼び出します ====");
        SubclassA classA = new SubclassA();
        init(classA);
        System.out.println("==== SubclassB型の変数でinitを呼び出します ====");
        SubclassB classB = new SubclassB();
        init(classB);
        System.out.println("==== SubclassB型の変数でキャストしてinitを呼び出します ====");
        init((SubclassB) classB);
        System.out.println("==== SubclassB型の変数でthisで修飾してinitを呼び出します ====");
        this.init(classB);
        System.out.println("==== SubclassB型の変数でキャストしてthisで修飾してinitを呼び出します ====");
        this.init((SubclassB) classB);
    }

    /* 継承元のinitメソッド */
    public void init(OverloadTest test) {
        System.out.println("OverloadTest#init(OverloadTest)です。");
    }

    /* OverloadTestを継承したクラスA */
    public class SubclassA extends OverloadTest {
        /* 継承元のinitメソッドをオーバーライド */
        public void init(OverloadTest test) {
            System.out.println("SubclassA#init(OverloadTest)です。");
        }
    }

    /* OverloadTestを継承したクラスB */
    public class SubclassB extends OverloadTest {
        /* 継承元のinitメソッドを継承したクラスBの型でオーバーロード */
        public void init(SubclassB test) {
            System.out.println("SubclassB#init(SubclassB)です。");
        }
    }

}

サンプルコードでの実行結果

■■■ OverloadTestの挙動 ■■■
==== OverloadTest型の変数でinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
OverloadTest#init(OverloadTest)です。
OverloadTest#init(OverloadTest)です。
==== SubclassA型の変数でinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
==== SubclassB型の変数でinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
==== SubclassB型の変数でキャストしてinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
==== SubclassB型の変数でthisで修飾してinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
==== SubclassB型の変数でキャストしてthisで修飾してinitを呼び出します ====
OverloadTest#init(OverloadTest)です。

■■■ SubclassAの挙動 → オーバーライドしているため呼び出される ■■■
==== OverloadTest型の変数でinitを呼び出します ====
SubclassA#init(OverloadTest)です。
SubclassA#init(OverloadTest)です。
SubclassA#init(OverloadTest)です。
==== SubclassA型の変数でinitを呼び出します ====
SubclassA#init(OverloadTest)です。
==== SubclassB型の変数でinitを呼び出します ====
SubclassA#init(OverloadTest)です。
==== SubclassB型の変数でキャストしてinitを呼び出します ====
SubclassA#init(OverloadTest)です。
==== SubclassB型の変数でthisで修飾してinitを呼び出します ====
SubclassA#init(OverloadTest)です。
==== SubclassB型の変数でキャストしてthisで修飾してinitを呼び出します ====
SubclassA#init(OverloadTest)です。

■■■ SubclassBの挙動 → オーバーロードしているinit(SubclassB)は呼び出れない ■■■
==== OverloadTest型の変数でinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
OverloadTest#init(OverloadTest)です。
OverloadTest#init(OverloadTest)です。
==== SubclassA型の変数でinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
==== SubclassB型の変数でinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
==== SubclassB型の変数でキャストしてinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
==== SubclassB型の変数でthisで修飾してinitを呼び出します ====
OverloadTest#init(OverloadTest)です。
==== SubclassB型の変数でキャストしてthisで修飾してinitを呼び出します ====
OverloadTest#init(OverloadTest)です。

実際の対応

オーバーロードである必要性はなかったので、オーバーライドしてから型変換するという対応とした。

public class SubclassB extends OverloadTest {
    /* 継承元のinitメソッドをオーバーライド */
    public void init(OverloadTest arg ) {
        // SubclassBに型変換
        SubclassB test = (SubclassB) arg ;
        /* 
         * SubclassBでの処理
         */
    }
}