オーバーロード(多重定義)は、同じ名前のメソッドなどを、引数の型や個数が異なるように複数定義することです。例えば整数2個を足すaddと、小数2個を足すaddを、同じ名前で使えるようにします。
この記事ではJavaのメソッドを例に説明します。区別に使う条件や選択の仕組みは言語によって異なるため、Javaの規則をすべての言語にそのまま当てはめないようにしましょう。末尾では、オブジェクト指向をまとめて復習できるnote教材を案内します。
何を変えるとオーバーロードになる?
| 変更点 | Javaで区別できる例 | 注意点 |
|---|---|---|
| 引数の個数 | add(int, int)とadd(int, int, int) | 2個と3個で異なる |
| 引数の型 | add(int, int)とadd(double, double) | 型の組合せが異なる |
| 引数の型の並び | format(String, int)とformat(int, String) | 並べ替えた結果、型の並びが変わる |
| 引数名だけ | add(int a, int b)とadd(int x, int y) | 区別できない |
| 戻り値の型だけ | int size()とdouble size() | これだけでは区別できない |
「引数の順番を変える」は、引数名を入れ替えるという意味ではありません。int、intという同じ型の並びのままでは、名前を変えても別のメソッドとして定義できません。
具体例:同じaddで整数と小数を足す
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}
| 呼出し例 | 選ばれるメソッド | 結果 |
|---|---|---|
| calc.add(2, 3) | add(int, int) | 5 |
| calc.add(2.5, 3.0) | add(double, double) | 5.5 |
| calc.add(2, 3, 4) | add(int, int, int) | 9 |
calcはCalculatorのインスタンスとします。利用側はaddという共通の名前を使い、コンパイラが呼出し時の引数に適用できる候補を調べます。この例では型と個数が明確に異なるため、選ばれるメソッドを確認しやすくなっています。
戻り値だけでは区別できない理由
Javaではメソッドの区別に、名前と引数の型の並びなどを使います。戻り値の型だけを変えても、同じ引数で別のメソッドとしてオーバーロードすることはできません。
例えばint size()とdouble size()を同じクラスに定義することはできません。一方、引数が異なって正しくオーバーロードされていれば、それぞれの戻り値の型が異なること自体は可能です。「戻り値を変えてはいけない」と覚えるのも誤りです。
オーバーライドとの違い
| 観点 | オーバーロード | オーバーライド |
|---|---|---|
| 基本 | 同名で引数の異なる候補を用意する | 継承したインスタンスメソッドを子クラスで再定義する |
| 引数の型の並び | 候補間で異なる | 原則として同じシグネチャのメソッドを対象にする |
| 継承の必要性 | 同じクラス内でも可能。継承を必須としない | 親子関係など、継承したメソッドとの関係がある |
| Javaの選択の捉え方 | コンパイル時にオーバーロード候補を選択 | オーバーライドされた実装は実際のオブジェクトに応じて実行時に決まる |
Javaでは、親クラスから継承したメソッドと同じ名前で引数を変え、オーバーロードになる場合もあります。「同一クラス内だけでしか起きない」と限定しないようにしましょう。戻り値の互換性やアクセス制御など、オーバーライドには別の規則もあります。
呼出し側の型と曖昧さにも注意
Javaのオーバーロード選択では、呼出し式の引数の型を基に候補を調べ、必要に応じて型変換なども考慮します。実際のオブジェクトの型を実行時に見て、すべての同名メソッドから毎回選び直す仕組みではありません。
例えばObject型の変数にStringの実体を入れていても、その変数を引数として渡す呼出しでは、まず変数の宣言上の型などに基づいてオーバーロード解決が行われます。複数候補から最も適切なものを決められなければ、Javaでは曖昧な呼出しとしてコンパイルエラーになる場合があります。
同じ名前にするのは、意味の近い操作
同じ名前で扱えることは便利ですが、無関係な処理を同じ名前に集めれば分かりやすくなるとは限りません。addなら値を加えるなど、呼出し側が予測できる意味をそろえ、似た型の候補を増やしすぎない設計が大切です。
確認問題:どの組合せが有効?
Javaで同じクラスに定義するとき、次のどれがオーバーロードとして成立するでしょうか? ①int size()とdouble size() ②add(int a, int b)とadd(int x, int y) ③add(int, int)とadd(double, double)。③は適切な戻り値と本体を持つものとします。
解答・解説を見る
③です。引数の型の並びが異なります。①は戻り値の型だけ、②は引数名だけの違いなので、Javaでは別のオーバーロードとして区別できません。
noteでオブジェクト指向の用語をつなげる
オーバーロードとオーバーライドの違いが分かったら、関連noteでクラス・継承・カプセル化・多態性をまとめて確認できます。リンク先ではオーバーライドとオーバーロードも扱っています。本記事の具体例を押さえ、オブジェクト指向全体の中で用語を整理しましょう。
教材の公開範囲・価格はnoteの表示をご確認ください。ほかの教材は著者のnote一覧から探せます。
まとめ
オーバーロードは同じ名前で異なる引数の候補を定義します。Javaでは引数名や戻り値だけでは区別できません。オーバーライドは継承したメソッドの再定義であり、候補の選択と実行時の実装の選択を分けて考えましょう。
参考:Oracle Java Tutorials:Defining Methods(英語)。コード例と確認問題は本記事のオリジナルです。

コメント