抽象クラスと抽象メソッド
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 32/87。
時として、設計図として機能するものの、直接インスタンス化されるべきではないクラスを定義したい場合があります。例えば、汎用的な Shape クラスは親クラスとして理にかなっていますが、特定の形を持たない「図形」とはどのようなものでしょうか?ここで抽象クラスの出番です。
抽象クラスは、abstractキーワードを使用して宣言され、インスタンス化することはできません。これには、実装を持つ通常のメソッドと、ボディを持たない抽象メソッドの両方を含めることができます。
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// 抽象メソッド - 実装なし
public abstract double getArea();
// 通常のメソッド - 実装あり
public String getColor() {
return color;
}
}抽象メソッドは、サブクラスが何をしなければならないかを宣言しますが、どのようにするかは宣言しません。抽象クラスを継承する非抽象クラスはすべて、すべての抽象メソッドの実装を提供しなければなりません:
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}抽象クラスを参照型として使用することで、ポリモーフィズムを実現できます。
Shape shape = new Circle("red", 5.0);
System.out.println(shape.getArea()); // Circleの実装を呼び出します抽象クラスは、サブクラスが共通のコードを共有しつつ、特定の振る舞いをそれぞれ異なる方法で実装する必要がある場合に理想的です。これらはコードの再利用を可能にしながら、規約を強制します。
チャレンジ
簡単抽象クラスの力を実証する家電システムを構築しましょう。すべての家電が何をすべきかを定義するベースとなる Appliance クラスを作成し、具体的な家電の種類ごとに、それをどのように実行するかを正確に決定させます。
コードは4つのファイルに分けて構成します:
Appliance.java: すべての家電の設計図となる抽象クラスを作成します。すべての家電はbrandフィールド (String) とwattageフィールド (int) を持ちます。両方のフィールドを初期化するコンストラクタ、それぞれのゲッターメソッド、および[brand] - [wattage]Wを返す通常のメソッドgetInfo()を含めてください。サブクラスが実装しなければならない抽象メソッドoperate()を定義します。これは、各家電がその主要な機能をどのように実行するかを表します。WashingMachine.java: Appliance を継承する具体的なクラスを作成します。洗濯機には、kg 単位の洗濯容量を表す追加のcapacityフィールド (int) があります。親クラスの初期化を処理するためにsuperを使用してください。operate()メソッドを実装して、[brand] washing machine is washing [capacity]kg of clothesと出力するようにします。Microwave.java: Appliance を継承する別の具体的なクラスを作成します。電子レンジには、出力レベルのパーセンテージを表すpowerフィールド (int) があります。operate()を実装して、[brand] microwave is heating at [power]% powerと出力するようにします。Main.java: ポリモーフィズムを使用してすべてをまとめます。5つの入力(ブランド名、ワット数、洗濯機の容量、別のブランド名、電子レンジの出力レベル)を受け取ります。WashingMachine と Microwave を作成し、それらをAppliance参照の配列に格納します。配列をループで回し、各家電についてgetInfo()を使用して情報を出力した後、operate()を呼び出します。
入力は、最初のブランド (String)、最初のワット数 (int)、kg 単位の容量 (int)、2番目のブランド (String)、出力レベル (int) の順で5つ受け取ります。
出力は4行になります。各家電について、情報の行に続いて動作の振る舞いが表示されます。抽象クラスによって、異なる家電を統一的に扱いながら、それぞれが独自の方法で動作する様子に注目してください!
チートシート
抽象クラスは abstract キーワードを使用して宣言され、直接インスタンス化することはできません。これはサブクラスの設計図として機能します:
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Abstract method - no implementation
public abstract double getArea();
// Regular method - has implementation
public String getColor() {
return color;
}
}抽象メソッドはメソッド本体を持たず、抽象クラスではないサブクラスによって実装される必要があります:
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}抽象クラスは、ポリモーフィズムのための参照型として使用できます:
Shape shape = new Circle("red", 5.0);
System.out.println(shape.getArea()); // Calls Circle's implementation抽象クラスは、サブクラスが共通のコードを共有しつつ、特定の振る舞いを異なる方法で実装する必要がある場合に最適です。
自分で試してみよう
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 入力を読み込む
String brand1 = scanner.nextLine();
int wattage1 = scanner.nextInt();
int capacity = scanner.nextInt();
scanner.nextLine(); // 改行文字を消費する
String brand2 = scanner.nextLine();
int power = scanner.nextInt();
// TODO: brand1、wattage1、capacity を使用して WashingMachine オブジェクトを作成する
// TODO: brand2、wattage1(または適切なワット数)、power を使用して Microwave オブジェクトを作成する
// TODO: Appliance 参照の配列を作成し、両方のオブジェクトを格納する
// TODO: 配列をループで回し、各家電(appliance)に対して以下を行う:
// - getInfo() を使用してその情報を表示する
// - operate() を呼び出す
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造