今回も問題を解いていきましょう。
問題
次のプログラムを実行した場合の出力はどれでしょうか?正しい選択肢を選んでください。
abstract class Vehicle {
abstract void makeSound();
}
class Car extends Vehicle {
void makeSound() {
System.out.println("Vroom");
}
}
class Truck extends Vehicle {
void makeSound() {
System.out.println("Honk");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myVehicle = new Truck();
myVehicle.makeSound();
}
}
選択肢
- A. Vroom
- B. Honk
- C. コンパイルエラー
- D. 実行時エラー
答えと解説
回答を見る
答え
B. Honk
基本説明
今回のプログラムでは、抽象クラスVehicle
を使用しています。抽象クラスには抽象メソッドmakeSound
があり、これは具体的な実装を持たない設計図のようなものです。
その具体的な実装は、Vehicle
を継承したCar
とTruck
クラスが持っています。このようにして、サブクラスで具体的な振る舞いを実現します。
質問のプログラムでは、Vehicle
型の変数myVehicle
はTruck
のインスタンスを指しているため、Truck
クラスで実装されたmakeSound
が呼び出され、「Honk」が出力されます。
誤答理由
選択肢Aの「Vroom」を選んだ場合は、Car
が正しくインスタンス化されていると考えた可能性があります。しかし、実際にはTruck
がインスタンス化されているため、誤答となります。
選択肢Cの「コンパイルエラー」は、抽象メソッドが正しくオーバーライドされているため発生しません。選択肢Dの「実行時エラー」は、プログラム内で特に例外が投げられるようなコードがないため、これも誤答です。
つまずきポイント
抽象クラスやメソッドの使い方を間違えると、意図した動作を得られません。抽象クラスは実装を持たないメソッドを含むことができ、そのメソッドはサブクラスで具現化する必要があります。
また、インスタンスの型と変数の型が異なる場合、実行時にはインスタンスの型に基づいたメソッドが呼び出されるため、これを理解していないと意図しない出力に戸惑う可能性があります。
発展知識
抽象クラスを使用する理由として、共通のインターフェースを用意しつつ、具体的な実装をサブクラスに任せるという設計方針があります。
Javaではインターフェースも同様の設計を実現できますが、抽象クラスは状態を持ったり、具体的に実装済みのメソッドを含むことができる点で、インターフェースよりも柔軟性があります。
両者の使い分けは設計のコンテキストに依存しますが、適切に利用することでコードの再利用性や拡張性が高まる利点があります。