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

入門 | 10分 で読める | 2026.05.02

公式ドキュメント

このシリーズについて

「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 の基本 で、クラスに紐づくメンバーと変更不可の仕組みを学びます。

まとめ

この記事では、手順を追って動かしながら重要な確認ポイントを押さえることが大切です。まずは学習用の最小構成で動作確認し、本番利用する前にセキュリティ、権限、エラー処理、運用手順を見直してください。

参考リソース

← 一覧に戻る
PR
PR
PR
PR