Java入門 #24 - 抽象クラス(abstract class)

入門 | 10分 で読める | 2026.05.02

公式ドキュメント

この記事の要点

abstract class は「一部だけ実装を持つ」親クラス
• `abstract` メソッドはサブクラスが**必ず実装**しなければならない
• 抽象クラスは インスタンス化できない(サブクラス経由で使う)

このシリーズについて

「Java入門」は1本1テーマで進むシリーズです。本記事は第24回として、抽象クラス(abstract class)を扱います。

前提条件: Java入門 #21 - 継承(extends)Java入門 #23 - インターフェース を読んでいること。クラス・継承・インターフェースの理解が必要です。

抽象クラスとは

抽象クラス(abstract class)は、一部のメソッドを未実装のまま残しておく ことができるクラスです。通常のクラスとインターフェースの中間的な存在で、次のような特徴があります。

項目抽象クラスインターフェース通常のクラス
宣言abstract class Shapeinterface Drawableclass Circle
抽象メソッド持てる(abstract 付き)デフォルトで抽象メソッド持てない(全部実装が必要)
通常のメソッド持てる(実装あり)default / static メソッドのみ持てる
フィールド持てる(状態を持てる)public static final のみ持てる
コンストラクタ持てる(サブクラスから呼ばれる)持てない持てる
インスタンス化できないできないできる
継承 / 実装1つのクラスのみ extends複数 implements1つのクラスのみ extends

抽象クラスの宣言

abstract キーワードを付けてクラスを宣言します。

// Shape.java(抽象クラス)
public abstract class Shape {
    private String name;

    // コンストラクタは持てる
    public Shape(String name) {
        this.name = name;
    }

    // 通常のメソッド(実装あり)
    public String getName() {
        return name;
    }

    // 抽象メソッド(実装なし)
    public abstract double getArea();
    public abstract double getPerimeter();
}

抽象クラスは インスタンス化できません

Shape s = new Shape("未定義");  // コンパイルエラー!
// → 'Shape' is abstract; cannot be instantiated

抽象メソッドとは

抽象メソッド(abstract method)は、メソッドの宣言だけあって実装がない メソッドです。abstract キーワードを付けて宣言します。

public abstract double getArea();  // 実装なし(セミコロンで終わる)

抽象メソッドを持つクラスは、必ず abstract class として宣言 しなければなりません。

サブクラスでの実装義務

抽象クラスを継承したサブクラスは、すべての抽象メソッドを実装しなければなりません。実装しないとコンパイルエラーになります。

// Circle.java(具象クラス)
public class Circle extends Shape {
    private double radius;

    public Circle(String name, double radius) {
        super(name);  // 親のコンストラクタを呼ぶ
        this.radius = radius;
    }

    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public double getPerimeter() {
        return 2 * Math.PI * radius;
    }
}

// Rectangle.java(具象クラス)
public class Rectangle extends Shape {
    private double width;
    private double height;

    public Rectangle(String name, double width, double height) {
        super(name);
        this.width = width;
        this.height = height;
    }

    @Override
    public double getArea() {
        return width * height;
    }

    @Override
    public double getPerimeter() {
        return 2 * (width + height);
    }
}

// Main.java(Java 21)
public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle("円", 5.0);
        Shape rect = new Rectangle("長方形", 4.0, 6.0);

        System.out.println(circle.getName() + " 面積: " + circle.getArea());
        System.out.println(rect.getName() + " 面積: " + rect.getArea());
    }
}

実行結果:

円 面積: 78.53981633974483
長方形 面積: 24.0

ポイント: 抽象クラスは「共通の処理は親が実装し、個別の処理は子に任せる」設計パターン(Template Method パターン)でよく使われます。

コンストラクタの扱い

抽象クラスは コンストラクタを持てます。サブクラスのコンストラクタから super() で呼ばれます。

// Animal.java(抽象クラス)
public abstract class Animal {
    private String species;

    // コンストラクタ
    public Animal(String species) {
        this.species = species;
        System.out.println(species + " を作成");
    }

    public abstract void makeSound();
}

// Dog.java
public class Dog extends Animal {
    public Dog() {
        super("犬");  // 親のコンストラクタを呼ぶ
    }

    @Override
    public void makeSound() {
        System.out.println("ワン!");
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();  // → 犬 を作成
        dog.makeSound();      // → ワン!
    }
}

注意: 抽象クラス自体は `new Animal()` でインスタンス化できません。あくまでサブクラス経由で使います。

抽象クラス vs インターフェース

どちらを使うべきかは、設計の目的によって変わります。

使い分け抽象クラスインターフェース
「is-a 関係」を表す◎(Dog extends Animal
「can-do 関係」を表す◎(Dog implements Runnable
共通の状態(フィールド)を持つ◎(name, age など)✗(定数のみ)
共通の実装を持つ◎(通常のメソッド)△(default メソッド)
複数を継承 / 実装したい✗(1つのみ)◎(複数可)
コンストラクタで初期化

使い分けの例

// 抽象クラス: 動物という「種類」を表す
public abstract class Animal {
    private String name;  // 共通の状態

    public Animal(String name) {
        this.name = name;
    }

    public abstract void makeSound();
}

// インターフェース: 「走れる」という能力を表す
public interface Runnable {
    void run();
}

// Dog は動物(is-a)であり、走れる(can-do)
public class Dog extends Animal implements Runnable {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println("ワン!");
    }

    @Override
    public void run() {
        System.out.println("走る");
    }
}

学習のヒント: 「共通の状態やロジックを持つなら抽象クラス、役割や能力を表すならインターフェース」と覚えましょう。

実践例: テンプレートメソッドパターン

抽象クラスは、処理の流れを親が決めて、細部を子に任せる 設計によく使われます。

// Game.java(抽象クラス)
public abstract class Game {
    // テンプレートメソッド(流れを定義)
    public final void play() {
        initialize();
        startPlay();
        endPlay();
    }

    // 共通処理
    private void initialize() {
        System.out.println("ゲームを初期化");
    }

    // 抽象メソッド(子クラスが実装)
    protected abstract void startPlay();
    protected abstract void endPlay();
}

// Chess.java
public class Chess extends Game {
    @Override
    protected void startPlay() {
        System.out.println("チェスを開始");
    }

    @Override
    protected void endPlay() {
        System.out.println("チェスを終了");
    }
}

// Shogi.java
public class Shogi extends Game {
    @Override
    protected void startPlay() {
        System.out.println("将棋を開始");
    }

    @Override
    protected void endPlay() {
        System.out.println("将棋を終了");
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        Game chess = new Chess();
        chess.play();
        // → ゲームを初期化 → チェスを開始 → チェスを終了

        System.out.println();

        Game shogi = new Shogi();
        shogi.play();
        // → ゲームを初期化 → 将棋を開始 → 将棋を終了
    }
}

play() の処理の流れは親クラスが決めて、startPlay() / endPlay() の中身は子クラスに任せています。

まとめ

概念説明
abstract class一部のメソッドを未実装のまま残せるクラス
abstract メソッド実装を持たないメソッド(サブクラスが必ず実装)
インスタンス化抽象クラスは new できない(サブクラス経由で使う)
コンストラクタ抽象クラスも持てる(super() で呼ばれる)
使い分け共通の状態やロジックがあるなら抽象クラス、役割や能力を表すならインターフェース

次のステップ

Java入門 #25 - static と final の基本 で、クラスに紐づくメンバーと変更不可の仕組みを学びます。

参考リソース

この技術を体系的に学びたいですか?

未来学では東証プライム上場企業のITエンジニアが24時間サポート。月額24,800円から、退会金0円のオンラインIT塾です。

メールで無料相談する
← 一覧に戻る