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

入門 | 10分 で読める | 2026.05.02

公式ドキュメント

このシリーズについて

「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 - インターフェース で、クラス階層とは別に「契約」を定義する仕組みを学びます。

まとめ

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

参考リソース

← 一覧に戻る
PR
PR
PR
PR