23.

Java 抽象クラス・抽象メソッド完全ガイド

編集
この記事の要点
  • abstract class はインスタンス化できないクラス。共通実装+"サブクラスで実装させたいメソッド"を持てる
  • abstract method はメソッド本体を持たない宣言だけのメソッド。サブクラスで @Override 実装が強制される
  • abstractfinal併用不可。継承できないクラスは抽象にできない
  • interface との違い: 抽象クラスは"状態 (フィールド) + コンストラクタ"を持てる。Java 8+ の interface default メソッドで境界が曖昧化
  • 現代の設計指針: Composition > Inheritance。Template Method パターンが使えるなら抽象クラス、それ以外は interface + 委譲

抽象クラスの基本

// abstract クラス: インスタンス化できない
public abstract class Animal {
    private final String name;

    // ★ 抽象クラスもコンストラクタを持てる
    protected Animal(String name) {
        this.name = name;
    }

    // 共通実装 (具象メソッド)
    public String getName() {
        return name;
    }

    // 抽象メソッド: サブクラスで実装強制
    public abstract String cry();
}

// 具象サブクラス
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public String cry() {
        return "ワン";
    }
}

// 使い方
Animal a = new Animal("a");  // ❌ コンパイルエラー
Animal d = new Dog("ポチ");  // ✅ サブクラス経由でインスタンス化
System.out.println(d.cry()); // ワン

abstract の制約まとめ

項目抽象クラス抽象メソッド
インスタンス化不可 (new 不可)
本体持てる (フィールド、具象メソッド、コンストラクタ)持てない ({} なし)
final 併用不可 (継承前提なので矛盾)不可 (オーバーライド前提)
private 併用OK (内部クラスなら)不可 (サブクラスから見えない)
static 併用OK (内部クラスなら)不可 (static は継承で上書き不可)
サブクラスでの実装全抽象メソッドを実装 or サブクラスも abstract に必須 (実装しないなら自身も abstract)

interface との違い

// interface: 純粋な契約 (Java 7 以前)
public interface Flyable {
    void fly();
}

// Java 8+ default メソッド導入で interface も実装を持てる
public interface Swimmable {
    default void swim() {
        System.out.println("デフォルト遊泳");
    }

    // private メソッド (Java 9+)
    private void helper() { ... }

    // static メソッド (Java 8+)
    static Swimmable empty() { return () -> {}; }
}

// 抽象クラス: 状態を持てる
public abstract class Vehicle {
    protected int speed;        // フィールド
    protected Vehicle(int s) { this.speed = s; }  // コンストラクタ
    public abstract void move();
}
項目abstract classinterface
多重継承×(1 クラスのみ)○(複数 implements 可)
フィールド○(任意の修飾子)△(public static final のみ = 定数)
コンストラクタ×
具象メソッド○(任意)○(default / static / private)
状態 (state)×(default も状態は持てない)
用途共通実装+状態を共有する継承階層能力 (can-do) の宣言

典型パターン1: Template Method

抽象クラスの最頻出パターン。"アルゴリズムの骨格"を抽象クラスに定義し、可変部分をサブクラスに任せる:

public abstract class DataProcessor {
    // 骨格 (final で上書き禁止)
    public final void process() {
        var data = load();
        var result = transform(data);
        save(result);
    }

    protected abstract List<String> load();
    protected abstract List<String> transform(List<String> data);
    protected abstract void save(List<String> data);
}

public class CsvProcessor extends DataProcessor {
    @Override protected List<String> load() {
        return Files.readAllLines(Path.of("input.csv"));
    }
    @Override protected List<String> transform(List<String> data) {
        return data.stream().map(String::toUpperCase).toList();
    }
    @Override protected void save(List<String> data) {
        Files.write(Path.of("output.csv"), data);
    }
}

new CsvProcessor().process();  // 骨格に従って実行

典型パターン2: Strategy (interface 版)

// Strategy は interface の方が自然
public interface SortStrategy<T> {
    List<T> sort(List<T> data);
}

public class QuickSort<T extends Comparable<T>> implements SortStrategy<T> {
    @Override public List<T> sort(List<T> data) { ... }
}

public class Context<T> {
    private final SortStrategy<T> strategy;
    public Context(SortStrategy<T> s) { this.strategy = s; }
    public List<T> run(List<T> data) { return strategy.sort(data); }
}

// 利用
var ctx = new Context<>(new QuickSort<Integer>());
ctx.run(List.of(3, 1, 2));

Java 17 の sealed クラス

Java 17 で sealed が導入され、"継承を許可するサブクラスを明示"できるようになりました:

public sealed abstract class Shape
    permits Circle, Square, Triangle {
    public abstract double area();
}

public final class Circle extends Shape {
    private final double r;
    public Circle(double r) { this.r = r; }
    @Override public double area() { return Math.PI * r * r; }
}

// sealed なので Circle, Square, Triangle 以外は extends 不可
// → switch のパターンマッチで網羅性が型レベルで保証される
public double describe(Shape s) {
    return switch (s) {
        case Circle c   -> c.area();
        case Square sq  -> sq.area();
        case Triangle t -> t.area();
        // default 不要 (網羅されているため)
    };
}

いつ抽象クラスを使うか

状況推奨
共通のフィールドコンストラクタを共有abstract class
Template Method (骨格固定)abstract class + final 骨格メソッド
"できる能力"の宣言 (Flyable, Comparable など)interface
多重実装が必要interface
サブクラス集合を限定したいsealed class (Java 17+)
レコード型データrecord (継承不可)

現代の設計指針

Effective Java 等で繰り返し説かれる原則: Composition > Inheritance (継承より委譲)。安易な抽象クラスはサブクラスとの密結合を生むため、可能なら interface + final class + 委譲が推奨されます。

FAQ

Q: abstract class にコンストラクタは何のため?
A: サブクラスの super(...) 呼び出しで使われます。フィールド初期化は抽象クラスで集約できます。

Q: 抽象メソッドのアクセス修飾子は?
A: public / protected / パッケージプライベートは OK。private は不可 (オーバーライドできないため)。

Q: interface だけで全部書けるなら abstract class は不要?
A: 状態 (フィールド) を共有したい・コンストラクタで不変条件を確立したい場合は abstract class が必要です。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本的なルール
  2. データ型
  3. 変数
  4. 定数
  5. 配列
  6. コレクション(List,Set,Queue)
  7. Map(連想配列)
  8. 演算子
  9. 条件分岐
  10. 繰り返し制御文
  11. クラス
  12. メソッド
  13. インスタンス化
  14. コンストラクタ
  15. staticキーワード
  16. オーバーロード
  17. 継承
  18. オーバーライド
  19. this
  20. super
  21. パッケージ
  22. アクセス修飾子
  23. 抽象クラス・メソッド
  24. インターフェース
  25. カプセル化
  26. データベース接続
  27. セッション
  28. ファイル入出力
  29. ラムダ式

最近更新/作成されたページ