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

入門 | 10分 で読める | 2026.05.02

公式ドキュメント

今回やること

抽象クラスは、子クラスで共有する状態と処理を持ちながら、一部のメソッドを未実装で残せるクラスです。イベント名は共通に持ち、料金計算はチケット種別ごとに必ず実装させます。

前提: Java入門 #21 - 継承#22 - ポリモーフィズム#23 - インターフェースを終えていること。

Ticket(抽象クラス)
├── 共通: eventName、showEvent()
└── 未実装: price()
    ├── AdultTicketが実装
    └── StudentTicketが実装

1. 共通部分を抽象クラスへ置く

abstract class Ticket {
    private String eventName;

    Ticket(String eventName) {
        this.eventName = eventName;
    }

    void showEvent() {
        System.out.println("イベント: " + eventName);
    }
}

抽象クラスも、通常のフィールド、コンストラクタ、実装済みメソッドを持てます。ただしabstract classnew Ticket(...)で直接作ることはできません。

2. 子に実装させるメソッドを宣言する

チケット種別によって料金が違うため、親では処理内容を決めず、抽象メソッドとして宣言します。

abstract int price();

抽象メソッドには本体の波括弧がなく、末尾を;にします。具体的な子クラスは、抽象メソッドを実装しない限りインスタンス化できません。

3. 子クラスで料金を実装する

class AdultTicket extends Ticket {
    AdultTicket(String eventName) {
        super(eventName);
    }

    @Override
    int price() {
        return 2000;
    }
}

@Overrideを付けると、親のメソッド名や引数を間違えた時にコンパイラが知らせます。学生用も同じ契約で別料金を返します。

完成コードを動かす

AbstractClassDemo.javaとして保存します。

abstract class Ticket {
    private String eventName;

    Ticket(String eventName) {
        this.eventName = eventName;
    }

    void showEvent() {
        System.out.println("イベント: " + eventName);
    }

    abstract int price();
}

class AdultTicket extends Ticket {
    AdultTicket(String eventName) {
        super(eventName);
    }

    @Override
    int price() {
        return 2000;
    }
}

class StudentTicket extends Ticket {
    StudentTicket(String eventName) {
        super(eventName);
    }

    @Override
    int price() {
        return 1200;
    }
}

public class AbstractClassDemo {
    public static void main(String[] args) {
        Ticket adult = new AdultTicket("文化祭ライブ");
        Ticket student = new StudentTicket("文化祭ライブ");

        adult.showEvent();
        System.out.println("一般: " + adult.price() + "円");
        System.out.println("学生: " + student.price() + "円");
    }
}
javac AbstractClassDemo.java
java AbstractClassDemo

変数の型をTicketにそろえても、実際のオブジェクトに応じたprice()が呼ばれます。これは前回までに学んだポリモーフィズムを、抽象メソッドの契約で保証した形です。

インターフェースとの役割の違い

この例で抽象クラスを使う理由は、eventNameという状態とコンストラクタ、showEvent()という共通実装を子へ渡したいからです。

欲しいもの選択の目安
密接な親子で状態・共通処理を共有抽象クラス
異なる種類へ同じ役割だけを約束インターフェース

詳しいインターフェースの定義は#23へ戻って確認してください。ここでは両方を同時に実装しません。

成功確認

イベント: 文化祭ライブ
一般: 2000円
学生: 1200円

親のshowEvent()を再利用し、2つの子が異なるprice()を返せれば成功です。

よくあるつまずき

抽象クラスを直接newする

new Ticket(...)はできません。実装を完成させたAdultTicketなどを作ります。

子クラスで抽象メソッドを実装しない

具体クラスはすべての抽象メソッドを実装します。未実装なら、その子クラス自身にもabstractが必要です。

何でも抽象クラスへ集める

密接な親子関係と共有状態がある時に使います。役割だけを表したい場合はインターフェースを検討します。

練習

抽象クラスDeliveryに宛先とshowAddress()を持たせ、抽象メソッドfee()を宣言してください。BikeDeliveryCarDeliveryで異なる料金を返します。

次のステップ

Java入門 #25 - staticとfinalで、クラス全体の共有値と再代入しない値を学びます。

参考リソース

← 一覧に戻る
PR
PR
PR
PR