DEV Community

TANIAOKA, Akihiro
TANIAOKA, Akihiro

Posted on

7章17

このJavaのコードは、クラスの継承とポリモーフィズムに関連しています。クラスAにはhelloメソッドがあり、"A"を出力します。クラスBはクラスAを継承しており、helloメソッドをオーバーライドして、"B"を出力します。

Mainクラスでは、まずA型のオブジェクトを作成しています。その後、このオブジェクトをB型にキャストして、変数bに割り当てています。最終的にb.hello()メソッドを呼び出します。この呼び出しでは、実際のオブジェクトの型がどれであるかが重要になります。ここでは、A型のオブジェクトをB型にキャストしようとしていますが、実際にはAのインスタンスですので、キャストは実行時エラーになる可能性があります。

この情報に基づいて、選択肢を見てみましょう:

A. Aが表示される
B. Bが表示される
C. Mainクラスでコンパイルエラーが発生する
D. 実行時に例外がスローされる

キャストはコンパイル時には検査されないため、コンパイルエラー(C選択肢)は発生しません。しかし、実行時には、AのインスタンスをBとして扱おうとするとClassCastExceptionが発生するため、正しい答えはDです。

追記

// クラスAの定義。これは基本的なクラスです。
class A {
    // helloメソッドは、コンソールに"A"と印刷します。
    void hello() {
        System.out.println("A");
    }
}

// クラスBの定義。クラスAを継承しています。
class B extends A {
    // クラスAのhelloメソッドをオーバーライドして、"B"を印刷します。
    void hello() {
        System.out.println("B");
    }
}

// メインクラス
public class Main {
    // Javaプログラムのエントリーポイント
    public static void main(String[] args) {
        // クラスAのインスタンスを作成
        A a = new A();
        // クラスAのインスタンスをクラスBとして扱うためにキャストし、変数bに割り当てる
        // しかし、aは実際にはBのインスタンスではないため、ここでClassCastExceptionがスローされる
        B b = (B) a;
        // bのhelloメソッドを呼び出す。もしbが実際にBのインスタンスであれば、"B"が印刷される。
        // ただし、上記のキャストが失敗するため、この行は実際には到達されない。
        b.hello();
    }
}
Enter fullscreen mode Exit fullscreen mode

コメントにあるように、コードのこの部分は実際には実行時にClassCastExceptionを引き起こします。この例外は、A型のオブジェクトをB型のオブジェクトにキャストしようとしたときに発生しますが、AのインスタンスはBのインスタンスではないためです。コードのこの特定の部分(B b = (B) a;)は、aBのインスタンスでない限り、常に例外をスローします。Javaでは、あるクラスのオブジェクトをそのサブクラスの型にキャストすることは、そのオブジェクトが実際にはそのサブクラスのインスタンスである場合にのみ許されます。

補足

スローされるClassCastExceptionを避けるためには、A型のオブジェクトをB型にキャストする代わりに、実際にB型のオブジェクトを作成して使用する必要があります。以下の変更を加えます:

public class Main {
    public static void main(String[] args) {
        // Bクラスのインスタンスを作成し、A型の変数aに割り当てる
        A a = new B();
        // aをB型にキャストし、B型の変数bに割り当てる
        // これは安全なキャストであり、ClassCastExceptionはスローされない
        // なぜなら、aは実際にBのインスタンスであるからです。
        B b = (B) a;
        // bのhelloメソッドを呼び出すと、Bクラスでオーバーライドされたメソッドが呼び出される
        // その結果、"B"が出力される。
        b.hello();
    }
}
Enter fullscreen mode Exit fullscreen mode

この変更により、aは実際にBクラスのインスタンスを指しているので、B型へのキャストは安全です。したがって、helloメソッドを呼び出すと、Bクラスにオーバーライドされたメソッドが実行され、結果として"B"が出力されます。

ただし、この場合、キャストは必要ありません。なぜならaはもともとB型のオブジェクトを指しており、ポリモーフィズムによりBクラスのhelloメソッドが呼び出されるからです。従って、より簡単に次のように書くこともできます:

public class Main {
    public static void main(String[] args) {
        // Bクラスのインスタンスを作成し、A型の変数aに割り当てる
        A a = new B();
        // A型の変数aを通してhelloメソッドを呼び出す
        // 実行時にはBクラスのhelloメソッドが呼び出され、"B"が出力される
        a.hello();
    }
}
Enter fullscreen mode Exit fullscreen mode

このようにすることで、同じ結果が得られ、コードもシンプルになります。

Top comments (0)