3秒でわかる
同じ呼び出しに対して型ごとに違う処理が動く性質。種類が増えるたびに条件分岐を書き足す作業をなくすために使う、オブジェクト指向の柱のひとつです。
もう少し詳しく
どういうものか
ポリモーフィズム(多態性)は、同じ名前の呼び出しに対して、対象の型ごとに違う処理が実行される性質です。犬にも猫にも speak() と声をかけると、犬は「ワン」、猫は「ニャー」と返します。呼ぶ側はどちらが来るかを知らないまま、共通の呼び方だけを覚えておけばよくなります。
なぜ必要か
種類ごとに違う処理を書く方法として、まず思いつくのは条件分岐です。ただしこの書き方だと、種類が 1 つ増えるたびに、その種類を扱っているすべての if を探して足すことになります。10 か所あれば 10 か所すべてに手を入れ、1 か所忘れればそこだけ動きません。ポリモーフィズムを使うと、追加するのは新しいクラス 1 つだけで、呼び出し側は 1 行も変わりません。
具体例
abstract class Payment {
abstract int fee(int amount);
}
class Card extends Payment {
int fee(int amount) { return amount * 3 / 100; }
}
class Convenience extends Payment {
int fee(int amount) { return 220; }
}
// 呼ぶ側は具体的な種類を知らない
int total(List<Payment> ways, int amount) {
int sum = 0;
for (Payment p : ways) sum += p.fee(amount);
return sum;
}支払い方法が増えても total は書き換えません。新しいクラスを 1 つ足すだけで済みます。
つまずきやすいところ
オーバーロード(引数の型や個数が違う同名メソッド)と混同されがちです。オーバーロードはコンパイル時にどれを呼ぶか決まり、ポリモーフィズムは実行時に実際の型を見て決まります。Java では、親クラス型の変数に子のインスタンスを入れても、子だけが持つメソッドは呼べない点でつまずきます。Python では継承が無くても同名メソッドさえあれば同じように扱えるため、感覚が言語ごとに違う点にも注意が要ります。
似た用語との違い
| 用語 | 中身 |
|---|---|
| ポリモーフィズム | 同じ呼び出しが型ごとに違う結果になる |
| 継承 | 親の実装を子が引き継ぐ仕組み |
| カプセル化 | 内部データを隠して操作だけ公開する |
| インターフェース | 実装を持たない、守るべき呼び出し口の約束 |
覚え方
種類ごとの if を書きたくなったら、その分岐がそのままクラスの候補です。分岐の数だけクラスを作れば、呼ぶ側の分岐は消えます。