ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
ポリモーフィズムとは
ポリモーフィズム(Polymorphism, 多態性, 多様性)はオブジェクト指向の三大要素(カプセル化・継承・ポリモーフィズム)の一つ。同じインタフェース(メソッド名・シグネチャ)で、対象オブジェクトの実体型に応じて異なる動作をする性質を指します。
Java の基本例: 動物の鳴き声
// 親クラス
public abstract class Animal {
public abstract String cry();
}
// 子クラス1
public class Dog extends Animal {
@Override
public String cry() { return "ワン!"; }
}
// 子クラス2
public class Cat extends Animal {
@Override
public String cry() { return "ニャー"; }
}
// 子クラス3
public class Cow extends Animal {
@Override
public String cry() { return "モー"; }
}
// 利用側
public class Main {
public static void main(String[] args) {
// 親型の変数に子の実体を入れる ← ここがポリモーフィズム
Animal[] zoo = { new Dog(), new Cat(), new Cow() };
for (Animal a : zoo) {
System.out.println(a.cry());
// 出力:
// ワン!
// ニャー
// モー
}
}
}
ポイントは Animal a(コンパイル時型)であっても、a.cry() 呼出時に実行時型(Dog/Cat/Cow)の cry() がディスパッチされること。これを 動的束縛 / late binding / virtual call と呼びます。
インターフェースによるポリモーフィズム
// 継承関係が無くても、共通インタフェースで多態化できる
public interface Payable {
void pay(int amount);
}
public class CreditCard implements Payable {
@Override public void pay(int amount) {
System.out.println("クレジットで " + amount + " 円決済");
}
}
public class PayPay implements Payable {
@Override public void pay(int amount) {
System.out.println("PayPay で " + amount + " 円決済");
}
}
public class BankTransfer implements Payable {
@Override public void pay(int amount) {
System.out.println("銀行振込で " + amount + " 円送金");
}
}
// 呼出側
public void checkout(Payable method, int amount) {
method.pay(amount); // method の実体次第で動作が変わる
}
C++ の virtual
C++ ではメソッドに virtual を付けないと動的束縛になりません:
#include
#include
#include
class Animal {
public:
virtual ~Animal() = default; // 仮想デストラクタ必須
virtual std::string cry() const = 0; // 純粋仮想関数
};
class Dog : public Animal {
public:
std::string cry() const override { return "ワン!"; }
};
class Cat : public Animal {
public:
std::string cry() const override { return "ニャー"; }
};
int main() {
std::vector> zoo;
zoo.push_back(std::make_unique());
zoo.push_back(std::make_unique());
for (const auto& a : zoo) {
std::cout << a->cry() << std::endl;
}
return 0;
}
もし cry() から virtual を外すと、コンパイル時型(Animal)の cry() が呼ばれてしまい多態化しません。
Python は鴨型付け(Duck Typing)
Python は型宣言なしで自然にポリモーフィズムを実現します:
class Dog:
def cry(self): return "ワン!"
class Cat:
def cry(self): return "ニャー"
# 継承関係なし、ただ cry() を持っていれば良い
for a in [Dog(), Cat()]:
print(a.cry())
# “Duck Typing”: アヒルのように鳴くものはアヒルとみなす
なぜポリモーフィズムが必要か
① Open-Closed Principle (OCP)
「拡張に対して開かれ、修正に対して閉じる」原則。新しい動物クラスを追加したとき、既存の呼出側コードを変更せずに済むのがポリモーフィズムの最大の利点です。
// ポリモーフィズム無し → 新しい動物を増やすたびに if 文を書き換える
public void cry(String kind) {
if (kind.equals("dog")) System.out.println("ワン!");
else if (kind.equals("cat")) System.out.println("ニャー");
else if (kind.equals("cow")) System.out.println("モー");
// ← Bird 追加で if 増殖
}
// ポリモーフィズム有り → 新しいクラスを足すだけ
public void cry(Animal a) {
System.out.println(a.cry());
}
// → class Bird extends Animal { String cry() { return "ピヨ"; }} を追加するだけ
② デザインパターンの基盤
| パターン | ポリモーフィズムの使い方 |
|---|---|
| Strategy | アルゴリズム(ソート、料金計算)を差し替え可能に |
| Factory Method | 生成する具体型を実装に隠蔽、戻り値はインタフェース |
| Template Method | 基底クラスで骨組み、サブクラスで穴を埋める |
| Observer | イベント受信者を Listener インタフェースで抽象化 |
| Decorator | 同じインタフェースで機能を重ねる |
| State | 状態遷移を State 実装の差し替えで表現 |
③ テスト容易性
本物の DB / 外部 API のかわりにモック実装を差し込める。これは依存性注入 (DI) と組み合わせて初めて成立する仕組みで、ポリモーフィズムが前提です。
public interface UserRepository {
User find(long id);
}
// 本番実装
public class JdbcUserRepository implements UserRepository { ... }
// テスト用モック
public class MockUserRepository implements UserRepository {
public User find(long id) {
return new User(id, "テストユーザ");
}
}
// 利用側はインタフェース型で受ける
public class UserService {
private final UserRepository repo;
public UserService(UserRepository repo) { this.repo = repo; }
public String greet(long id) { return "Hi " + repo.find(id).name(); }
}
// 本番: new UserService(new JdbcUserRepository())
// テスト: new UserService(new MockUserRepository())
ポリモーフィズムの種類
| 種類 | 説明 | 例 |
|---|---|---|
| サブタイプ(包含) | 継承 + override | 本記事の Animal / Dog / Cat |
| パラメトリック | 型パラメータで抽象化 | Java Generics, C++ template, Rust ジェネリクス |
| アドホック(オーバーロード) | 同名で異なるシグネチャ | Java の println(int) / println(String) |
| 強制(暗黙変換) | 型変換でメソッド適用 | Java の int → long 自動昇格 |
誤用と限界
- 継承の濫用: 何でも親に詰めて深い継承木 → 変更時の影響範囲が広がる。「継承より委譲」の原則も併用
- Liskov 置換原則 (LSP) 違反: 子が親の契約を破ると、呼出側で意外な挙動。「正方形は長方形のサブクラスにすべきか?」問題が有名
- ダウンキャストの多用:
Animal a; if (a instanceof Dog) ...はポリモーフィズムを台無し。動作はメソッドに移譲すべき
FAQ
Q: オーバーロード(同名・異引数)もポリモーフィズム?
A: アドホック多態として分類されるが、実行時型による分岐ではない(コンパイル時に決まる)。「真の多態」は通常サブタイプ多態を指す。
Q: Java のジェネリクスは?
A: パラメトリック多態。List / List が同じ List インタフェースで動く点でポリモーフィズムの一種。
Q: virtual を全メソッドに付けるのは?
A: C++ では性能オーバヘッド(vtable 経由呼出)あり。Java は全メソッド事実上 virtual。性能が問題なら final でオーバーライド禁止に。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
- オブジェクト指向の概念
- 継承の概念と必要性
- ポリモーフィズム(多様性)の概念と必要性
- 抽象クラスの概念と必要性
- インターフェースの概念と必要性
- カプセル化の概念と必要性
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Laravel キャッシュクリア完全ガイド(cache:clear / config:clear / 2026-05-18 07:42:07
- プロジェクトの作成と削除 2026-05-18 07:42:07
- インストール直後にNetbeansが反応しない 2026-05-18 07:42:07
- 動画やチャンネルの検索 2026-05-18 07:42:07
- APIキー取得方法 2026-05-18 07:42:07
- チャンネル情報の取得 2026-05-18 07:42:07
- API 入門 — Web API(REST / GraphQL / gRPC / 2026-05-18 07:42:07
- インストール(eclipseプラグイン) 2026-05-18 07:42:07
- Laravel「Dotenv values containing spaces must be surrounded 2026-05-18 07:42:07
- エラー一覧 2026-05-18 07:42:07
- curl: (51) SSL: certificate subject name '~' does not match 2026-05-18 07:42:07
- インストール方法(Windows版) 2026-05-18 07:42:07
- JSONから配列に変換 2026-05-18 07:42:07
- 処理を一定時間待つ 2026-05-18 07:42:07
- A non well formed numeric value encountered 2026-05-18 07:42:07
コメントを削除してもよろしいでしょうか?