タイトル: オーバーロード
SEOタイトル: Java メソッドオーバーロード完全ガイド
| この記事の要点 |
|
オーバーロードとは
同じ名前のメソッドを、引数の型や数を変えて複数定義すること。呼び出し側はコンパイル時に最適なメソッドが選択されます。
public class Printer {
// 同名 println を引数違いで複数定義
public void println(String s) { System.out.println(s); }
public void println(int n) { System.out.println(n); }
public void println(double d) { System.out.println(d); }
public void println(Object o) { System.out.println(o); }
public void println() { System.out.println(); }
}
Printer p = new Printer();
p.println("hello"); // String 版
p.println(42); // int 版
p.println(3.14); // double 版
p.println(); // 引数なし版
オーバーロードの条件
| 変更点 | オーバーロード可? |
|---|---|
| 引数の型が違う | ✅ OK |
| 引数の数が違う | ✅ OK |
| 引数の順序が違う (型違い) | ✅ OK (推奨はしない) |
| 引数名だけ違う | ❌ NG |
| 戻り値の型だけ違う | ❌ NG |
| throws 句だけ違う | ❌ NG |
| 修飾子 (static / final 等) だけ違う | ❌ NG |
// ❌ コンパイルエラー: 戻り値だけ違う
int sum(int a, int b) { return a + b; }
double sum(int a, int b) { return a + b; }
// ✅ 引数の型が違うのでオーバーロード成立
int sum(int a, int b) { return a + b; }
double sum(double a, double b) { return a + b; }
// ✅ 引数数違い
int sum(int a, int b) { return a + b; }
int sum(int a, int b, int c) { return a + b + c; }
コンストラクタのオーバーロード
public class User {
private String name;
private int age;
private String email;
// 全引数
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
// ✅ this(...) で他コンストラクタへ委譲
public User(String name, int age) {
this(name, age, "noemail@example.com");
}
public User(String name) {
this(name, 0);
}
public User() {
this("Anonymous");
}
}
new User("Taro", 25, "taro@x.com");
new User("Taro", 25);
new User("Taro");
new User();
可変長引数 (varargs)
// 「0 個以上の引数を受け取る」
public int sum(int... nums) {
int total = 0;
for (int n : nums) total += n;
return total;
}
sum(); // 0
sum(1); // 1
sum(1, 2, 3); // 6
sum(new int[]{1, 2, 3}); // 6 (配列を直接渡せる)
// オーバーロードと varargs の優先順位
public void f(int x) { System.out.println("int"); }
public void f(int... xs) { System.out.println("varargs"); }
f(1); // → "int" (より具体的なメソッドが優先)
// 可変長引数は ★ 引数リストの最後にだけ
public void log(String tag, Object... args) { ... } // ✅
// public void bad(Object... args, String tag) { ... } // ★ コンパイルエラー
自動型変換 (widening / boxing) と選択順
引数の型が完全一致しない場合、Java は次の順で最適なオーバーロードを探します:
- 完全一致
- widening (拡大変換 int → long → float → double)
- autoboxing (int ↔ Integer)
- varargs
public void f(long x) { System.out.println("long"); }
public void f(Integer x) { System.out.println("Integer"); }
public void f(Object x) { System.out.println("Object"); }
public void f(int... xs) { System.out.println("varargs"); }
f(10);
// 完全一致 (int) なし → widening (long) が当たる → "long"
// long を消すと…
// → Integer (autoboxing) → "Integer"
// 全部消すと…
// → varargs → "varargs"
ジェネリクスとオーバーロードの相互作用
// ❌ コンパイルエラー: 型消去後シグネチャが同じ
public void f(List<String> list) { ... }
public void f(List<Integer> list) { ... }
// → どちらも f(List) になり区別できない
// ✅ 一方をリネームするか、List 以外で区別
public void fString(List<String> list) { ... }
public void fInteger(List<Integer> list) { ... }
オーバーロード vs オーバーライド
| オーバーロード | オーバーライド | |
|---|---|---|
| 意味 | 同名で引数違いの複数メソッド | 親クラスのメソッドを子で再定義 |
| クラス関係 | 同一クラス内 (または継承先) | 親子クラス |
| シグネチャ | 引数違い | 引数 / 戻り値型 (共変まで OK) 同じ |
| 呼び出し決定 | コンパイル時 (静的) | 実行時 (動的、ポリモーフィズム) |
| static メソッド | オーバーロード可 | ★ オーバーライド不可 (隠蔽) |
| final メソッド | オーバーロード可 | ★ オーバーライド不可 |
| private メソッド | オーバーロード可 | 子クラスから見えない |
| 注釈 | 無し | @Override |
class Parent {
public void greet() { System.out.println("Hello"); } // メソッドA
public void greet(String n) { System.out.println("Hi " + n); } // メソッドB (オーバーロード)
}
class Child extends Parent {
@Override
public void greet() { System.out.println("こんにちは"); } // ★ オーバーライド
}
Parent p = new Child();
p.greet(); // "こんにちは" (動的ディスパッチ)
p.greet("Taro"); // "Hi Taro" (親の B が呼ばれる)
オーバーロード設計のベストプラクティス
- 同じ意味の処理のみオーバーロードする (引数違いで全く違う処理は別名に)
- 引数違いは互いに委譲する:
sum(a, b)→sum(a, b, 0)等 - varargs と通常メソッドを共存させると曖昧になる → 避ける
- 同一型を順序違いで複数定義 (
(int, String)と(String, int)) は読み手が混乱 → 別名推奨 - autoboxing / widening の選択ルールを意識。意図しないオーバーロードが選ばれる事故を防ぐ
FAQ
Q: println(int) と println(Object) 両方あるとき println(null) はどうなる?
A: 「最も具体的な」型が選ばれる規則により、参照型同士なら最も具体的なもの。null は基本型に当てはまらないので参照型側が選ばれる。
Q: static メソッドはオーバーロードできる?
A: できる。static 同士、または static と非 static の組合せも可。ただしオーバーライドはできない (隠蔽)。
Q: コンストラクタを this() 呼び出すときの注意
A: this(...) はコンストラクタ本体の最初の文でなければならない。super(...) も同様。