Javaの抽象クラスとメソッド呼び出しの仕組みを徹底解説
生徒
「抽象クラスで定義されたメソッドから、サブクラスのメソッドが呼び出されることってあるんですか?」
先生
「はい、抽象クラス内のメソッドで抽象メソッドを呼び出すと、サブクラスでオーバーライドされたメソッドが実行されます。コードを見ながら詳しく説明しますね!」
1. 抽象クラスとメソッド呼び出しの仕組み
抽象クラスは、オブジェクト指向プログラミングの重要な要素であり、継承を通じてコードの再利用性を向上させるために使われます。抽象クラスには、抽象メソッド(実装のないメソッド)と具象メソッド(実装を持つメソッド)の両方を定義できます。
抽象クラスのメソッド内で抽象メソッドを呼び出す場合、実際に実行されるのはサブクラスでオーバーライドされたメソッドです。以下のコードを例に考えてみましょう:
abstract class AbstractExample {
public void execute() {
System.out.println("Start");
run(); // 抽象メソッドを呼び出す
System.out.println("End");
}
protected abstract void run(); // 抽象メソッド
}
class SubExample extends AbstractExample {
@Override
protected void run() {
System.out.println("Running...");
}
}
public class Main {
public static void main(String[] args) {
AbstractExample example = new SubExample();
example.execute();
}
}
実行結果は次のようになります:
Start
Running...
End
このコードでは、executeメソッド内で呼び出されるrunメソッドが、サブクラスSubExampleの実装に置き換わっています。
2. サブクラスの抽象メソッド実装
サブクラスは、抽象クラスに定義された抽象メソッドをすべて実装する必要があります。実装しない場合、サブクラスも抽象クラスとして定義される必要があります。以下の例を見てみましょう:
abstract class AbstractVehicle {
public abstract void start();
public void stop() {
System.out.println("Vehicle stopped.");
}
}
class Car extends AbstractVehicle {
@Override
public void start() {
System.out.println("Car started.");
}
}
public class Main {
public static void main(String[] args) {
AbstractVehicle vehicle = new Car();
vehicle.start(); // 出力: Car started.
vehicle.stop(); // 出力: Vehicle stopped.
}
}
このコードでは、Carクラスが抽象メソッドstartを実装しています。そのため、抽象クラスAbstractVehicleを継承したクラスとして正常に動作します。
3. 実行時のメソッド解決
実行時のメソッド解決は、オブジェクトの実際の型に基づいて行われます。抽象クラス型の変数にサブクラスのインスタンスを代入しても、サブクラスでオーバーライドされたメソッドが実行されます。
実行時の動作を確認するには、次のコードを参考にしてください:
abstract class Animal {
public abstract void speak();
}
class Dog extends Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
class Cat extends Animal {
@Override
public void speak() {
System.out.println("Meow");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Dog();
myAnimal.speak(); // 出力: Woof
myAnimal = new Cat();
myAnimal.speak(); // 出力: Meow
}
}
4. 試験対策ポイント
- 抽象クラス内のメソッドから抽象メソッドを呼び出す場合、サブクラスでオーバーライドされたメソッドが実行される。
- 抽象クラスはインスタンス化できないが、型として使用可能。
- サブクラスは抽象メソッドをすべて実装する必要がある。
5. まとめ
本記事では、Javaの抽象クラスとそのメソッド呼び出しの仕組みについて解説しました。抽象クラスは、継承を通じて共通の動作を提供しつつ、特定の処理はサブクラスに委ねる柔軟な設計が可能です。また、抽象クラス内で抽象メソッドを呼び出すと、サブクラスでオーバーライドされた実装が実行されるという重要なポイントも理解しました。
さらに、抽象メソッドを実装しない場合は、サブクラスも抽象クラスとして定義する必要があることや、実行時のメソッド解決がオブジェクトの実際の型に基づいて行われる仕組みも確認しました。これらの知識は、オブジェクト指向プログラミングを深く理解し、効率的なコード設計を行う上で非常に役立ちます。
以下に抽象クラスの応用例を示します:
abstract class Appliance {
public abstract void turnOn();
public void turnOff() {
System.out.println("Turning off appliance.");
}
}
class WashingMachine extends Appliance {
@Override
public void turnOn() {
System.out.println("Washing Machine is now ON.");
}
}
class Refrigerator extends Appliance {
@Override
public void turnOn() {
System.out.println("Refrigerator is now ON.");
}
}
public class Main {
public static void main(String[] args) {
Appliance wm = new WashingMachine();
wm.turnOn(); // 出力: Washing Machine is now ON.
wm.turnOff(); // 出力: Turning off appliance.
Appliance rf = new Refrigerator();
rf.turnOn(); // 出力: Refrigerator is now ON.
rf.turnOff(); // 出力: Turning off appliance.
}
}
この例では、抽象クラスApplianceがWashingMachineやRefrigeratorという具体的なクラスに共通の動作を提供しつつ、個別の動作はサブクラスで実装しています。
生徒
「抽象クラスの使い方が少しわかった気がします!でも、インタフェースとはどう使い分ければいいんですか?」
先生
「良い質問ですね!抽象クラスは共通の動作を提供したいとき、インタフェースは『型』を共有したいときに使うと考えるといいですよ。用途によって適切なものを選びましょう。」
生徒
「サブクラスで抽象メソッドを必ず実装しなきゃいけないというルールも便利ですね。責任が明確になります!」
先生
「その通りです!抽象クラスとインタフェースを理解して、より良い設計を目指しましょう。」