3秒でわかる
中身のないメソッドを含められる、継承されて完成する前提のクラス。共通処理を親に置きつつ、違う部分だけ子に書かせるために使います。
もう少し詳しく
どういうものか
抽象クラスは、それ単体ではインスタンスを作れないクラスです。Java では abstract 修飾子を付けて宣言し、中身を書かない抽象メソッドを持てます。抽象メソッドを持つ子クラスは、それを実装しない限りやはり抽象クラスのままです。共通の処理は親に実装として置き、種類ごとに変わる部分だけを抽象メソッドとして子に押し付けられるのが特徴です。
なぜ必要か
図形を扱うプログラムを考えます。面積の求め方は円と長方形で違いますが、面積を求めてラベルを組み立てて出力する流れは同じです。この共通の流れを親に書き、面積の計算だけを抽象メソッドにしておけば、新しい図形を足すときに書く量は面積の計算だけで済みます。呼び出す側は親の型で受け取れるので、図形が増えても分岐を増やさずに済みます。
具体例
abstract class Shape {
abstract double area(); // 中身は子に任せる
String label() { // 共通処理は親が持つ
return getClass().getSimpleName() + " の面積は " + area();
}
}
class Circle extends Shape {
private final double r;
Circle(double r) { this.r = r; }
@Override double area() { return Math.PI * r * r; }
}Shape s = new Shape() と書くとコンパイルエラーになり、new Circle(2.0) だけが作れます。
似た用語との違い
| 比較点 | 抽象クラス | インタフェース |
|---|---|---|
| 継承できる数 | 1 つだけ | いくつでも実装できる |
| フィールド | 通常のフィールドを持てる | 定数のみ |
| コンストラクタ | 書ける | 書けない |
| 向いている場面 | 共通の実装を配りたい | 能力の約束だけを決めたい |
同じ種類のものが実装を分け合うなら抽象クラス、無関係な型に共通の振る舞いを持たせたいならインタフェースが素直です。
つまずきやすいところ
継承は 1 つしかできないので、抽象クラスを親に選ぶと他のクラスを継承する余地が消えます。迷ったらインタフェースを先に検討し、共通実装をどうしても配りたいときだけ抽象クラスにする、という順番が扱いやすいです。また、親のコンストラクタは子から必ず呼ばれます。引数付きのコンストラクタしか無い抽象クラスを継承すると、子で super の呼び出しを書かない限りコンパイルが通りません。