Java入門 #22 - ポリモーフィズム(多態性)

入門 | 10分 で読める | 2026.05.02

公式ドキュメント

この記事の要点

親クラス型の変数で子クラスのインスタンスを受け取れる
• 実際に呼ばれるメソッドは 実行時の型(動的バインディング)で決まる
• `instanceof` で型チェック、Java 16+ は パターンマッチング で簡潔に書ける

このシリーズについて

「Java入門」は1本1テーマで進むシリーズです。本記事は第22回として、ポリモーフィズム(多態性) を扱います。

前提条件: Java入門 #21 - 継承(extends) を読んでいること。クラス・メソッド・継承の基礎知識が必要です。

ポリモーフィズムとは

ポリモーフィズム(polymorphism = 多態性)は、同じ型で扱いながら、実際の動作は中身のクラスによって変わる 仕組みです。

例えば Animal 型の変数に Dog / Cat / Bird のインスタンスを代入でき、makeSound() を呼ぶと、実際に実行されるのは各クラスの実装になります。

// Animal.java(親クラス)
public class Animal {
    public void makeSound() {
        System.out.println("何か鳴く");
    }
}

// Dog.java(子クラス)
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("ワン!");
    }
}

// Cat.java(子クラス)
public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("ニャー");
    }
}

// Bird.java(子クラス)
public class Bird extends Animal {
    @Override
    public void makeSound() {
        System.out.println("チュン");
    }
}

// Main.java(Java 21)
public class Main {
    public static void main(String[] args) {
        Animal[] animals = {
            new Dog(),
            new Cat(),
            new Bird()
        };

        for (Animal a : animals) {
            a.makeSound();  // 実際の型に応じたメソッドが呼ばれる
        }
    }
}

実行結果:

ワン!
ニャー
チュン

配列の型は Animal[] ですが、中身は Dog / Cat / Bird です。makeSound() を呼ぶと、実際の型(動的型)のメソッド が実行されます。

静的型と動的型

ポリモーフィズムを理解するには、静的型(コンパイル時に決まる型)と動的型(実行時の実際の型)の違いを押さえましょう。

用語意味
静的型(Static Type)変数宣言で書いた型。コンパイラが見るAnimal a = ... → 静的型は Animal
動的型(Dynamic Type)実行時に代入された実際のインスタンスの型... = new Dog() → 動的型は Dog
Animal a = new Dog();
// 静的型: Animal
// 動的型: Dog

メソッド呼び出しで実際に実行されるのは 動的型 のメソッドです。これを 動的バインディング(dynamic binding)と呼びます。

ポイント: コンパイラは静的型だけを見て「このメソッドは呼べるか」をチェックします。しかし実行時には動的型のメソッドが呼ばれます。

ポリモーフィズムの利点

なぜ親型でまとめて扱うのでしょうか?主に次の利点があります。

  1. 配列・コレクションで一括管理できる
    Animal[]List<Animal> に異なる種類の動物を入れて回す

  2. 共通の処理を書ける
    「全員 makeSound() を呼ぶ」というループを、個別の型を気にせず書ける

  3. 後から新しい子クラスを追加しやすい
    Fish クラスを追加しても、既存の Animal[] に入れるだけで動く

学習のヒント: ポリモーフィズムは「親型で受け取って、中身は自由に差し替える」設計パターンの基礎です。デザインパターン(Strategy, Template Method など)でも頻出します。

instanceof による型チェック

親型で受け取った変数が、実際にどのクラスのインスタンスかを調べたいときは instanceof 演算子を使います。

Animal a = new Dog();

if (a instanceof Dog) {
    System.out.println("これは Dog です");
}
演算子説明結果
a instanceof DogaDog またはそのサブクラスのインスタンスか?true / false
a instanceof AnimalaAnimal またはそのサブクラスのインスタンスか?DogAnimal を継承するので true

Java 16+ のパターンマッチング

Java 16 以降では、instanceof で型チェックと同時に キャスト変数を自動で作る ことができます(パターンマッチング)。

// 従来の書き方(Java 15 以前)
if (a instanceof Dog) {
    Dog dog = (Dog) a;  // 手動キャスト
    dog.wagTail();      // Dog 独自のメソッド
}

// Java 16+ のパターンマッチング
if (a instanceof Dog dog) {
    dog.wagTail();  // 自動的に Dog 型の変数 dog が使える
}

注意: パターンマッチング変数のスコープは `if` ブロック内のみです。`else` や外側では使えません。

実践例: List で異なる型をまとめる

配列だけでなく、List<Animal> のようなコレクションでもポリモーフィズムが使えます。

import java.util.List;

public class Main {
    public static void main(String[] args) {
        // Java 21 では List.of() で不変リストを作れる
        List<Animal> zoo = List.of(
            new Dog(),
            new Cat(),
            new Bird(),
            new Dog()
        );

        for (Animal animal : zoo) {
            animal.makeSound();

            // Bird だけ特別な処理
            if (animal instanceof Bird bird) {
                System.out.println("  → 飛べます");
            }
        }
    }
}

実行結果:

ワン!
ニャー
チュン
  → 飛べます
ワン!

まとめ

概念説明
ポリモーフィズム親型で受け取り、動的型に応じて動作が変わる仕組み
静的型変数宣言時の型。コンパイラが見る
動的型実行時の実際のインスタンスの型
動的バインディング実行時に動的型のメソッドが呼ばれる仕組み
instanceof実行時の型をチェックする演算子
パターンマッチング(Java 16+)instanceof Dog dog で型チェックと同時にキャスト変数を作る

次のステップ

Java入門 #23 - インターフェース で、クラス階層とは別に「契約」を定義する仕組みを学びます。

参考リソース

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

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

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