3秒でわかる
同じ名前のメソッドを、引数の型や個数を変えて複数定義すること。似た処理に別々の名前を付けずに済み、引数を省略した簡易版も用意できます。
もう少し詳しく
どういうものか
オーバーロードは、同一のクラス内に同じ名前のメソッドを複数定義し、引数の並び(シグネチャ)で使い分ける仕組みです。Javaでは引数の型、個数、順序のいずれかが違えば別のメソッドとして扱われます。どれが呼ばれるかは、実行時ではなくコンパイル時に引数の型を見て決まります。
戻り値の型だけを変えたものはオーバーロードになりません。int calc(int a) と double calc(int a) を並べるとコンパイルエラーです。呼び出し側の書き方から区別できないためです。
なぜ必要か
同じ意味の処理に別々の名前を付けると、使う側が名前を覚えきれません。printInt printDouble printString と並ぶより、すべて print で呼べる方が自然です。実際、Javaの System.out.println は10種類以上のオーバーロードを持ち、何を渡しても同じ書き方で出力できます。
引数を省略した簡易版を用意する使い方も多く、既定値の代わりになります。
具体例
class Receipt {
// 税率を指定して計算する本体
int total(int price, double taxRate) {
return (int) Math.floor(price * (1 + taxRate));
}
// 税率を省略したら10%として扱う
int total(int price) {
return total(price, 0.10);
}
// 複数商品にも対応する
int total(int[] prices, double taxRate) {
int sum = 0;
for (int p : prices) sum += p;
return total(sum, taxRate);
}
}簡易版から本体を呼ぶ形にしておくと、計算式が1か所に集まり、税率の扱いを直すときに1つのメソッドだけを見れば済みます。
つまずきやすいところ
自動型変換が絡むと、意図と違う定義が選ばれます。f(int) と f(long) があるところへ f('a') と文字を渡すと、char は int に広がるので f(int) が呼ばれます。曖昧で決められない場合はコンパイルエラーになり、f(Object) と f(String) に null を渡すと、より具体的な f(String) が選ばれます。判断に迷う組み合わせを作ってしまったら、素直に別名にした方が読み手に親切です。
オーバーライドとの混同も定番です。名前が似ていますが、別物です。
似た用語との違い
| 語 | 何をするか | 決まるタイミング |
|---|---|---|
| オーバーロード | 同じクラスで同名メソッドを引数違いで並べる | コンパイル時 |
| オーバーライド | 親クラスのメソッドを子クラスで置き換える | 実行時 |
オーバーライドはシグネチャを完全に一致させる必要があり、変えてしまうと置き換えではなくオーバーロードになります。この取り違えを防ぐために @Override を付けます。一致していなければコンパイラが指摘してくれます。
TypeScriptにもオーバーロードはありますが、実装は1つだけで、宣言を複数並べて型の見え方を変える形になります。実行時に分岐するコードは自分で書きます。