Java | 基礎文法:オーバーロード

Java Java
スポンサーリンク

オーバーロードの全体像

オーバーロードは「同じメソッド名に、引数の型・個数・並びが異なるバリエーションを定義する」仕組みです。呼び出し時の引数からコンパイラが最適な版を選びます。意味が近い処理を一つの名前でまとめられるため、API が覚えやすく、読みやすさも向上します。Java には「デフォルト引数」や「名前付き引数」がないので、柔軟な受け方はオーバーロードや可変長引数で表現します。


基本構文と呼び分け

同名・異なるシグネチャ(型/個数/並び)

static int sum(int a, int b) { return a + b; }
static double sum(double a, double b) { return a + b; }
static int sum(int a, int b, int c) { return a + b + c; }
Java

呼び出し側は引数の型・個数に応じて自動的に該当メソッドへルーティングされます。

可変長引数との併用

static int sum(int... nums) {
    int s = 0;
    for (int n : nums) s += n;
    return s;
}

sum(1);        // 1件
sum(1, 2, 3);  // 複数件
sum();         // 0件
Java

可変長(varargs)は「配列として受ける」特殊なオーバーロードです。必須項目がある場合は、必須を通常引数で先に受け、後半を可変長にすると意図が明確になります。


重要ポイントの深掘り:解決ルール(どれが選ばれるか)

最も適した版(最適一致→拡張→ボクシング→可変長)

  • ぴったり型一致の版が最優先で選ばれます。
  • 次に「プリミティブの拡張変換」(例:intlong)が検討されます。
  • その次に「ボクシング/アンボクシング」(例:intInteger)。
  • 最後の手段として可変長引数が選ばれます。
static void f(int x)   { System.out.println("int"); }
static void f(long x)  { System.out.println("long"); }
static void f(Integer x) { System.out.println("Integer"); }
static void f(int... x)  { System.out.println("varargs"); }

f(10);        // int
f(10L);       // long
Integer ix = 10;
f(ix);        // Integer
f();          // varargs
Java

「曖昧」になる組み合わせはコンパイルエラーになります。意図が伝わる型で呼ぶか、明示キャストで選択を確定させましょう。


重要ポイントの深掘り:曖昧さ・落とし穴・ベストプラクティス

曖昧なオーバーロードは避ける

static void g(Long x)  { }
static void g(Integer x) { }
// g(null); // どちらも受けられる → 曖昧でコンパイルエラー
Java

null を渡すと参照型版が複数候補になり曖昧になります。呼び出し側でキャストして明示するか、API 設計を見直します。

オートボクシングとプリミティブ拡張の競合

static void h(long x) { System.out.println("long"); }
static void h(Integer x) { System.out.println("Integer"); }
int n = 5;
h(n); // long が選ばれる(拡張優先、ボクシングより先)
Java

「どちらが選ばれるか」を開発者が即答できない設計は避け、シグネチャを簡潔にしましょう。

可変長引数は最後に一つだけ

可変長は末尾に1つだけ定義できます。オーバーロードと併用すると解決が複雑になりがちなので、「必須+可変」のシンプルな形に留めるのが安全です。

static String join(String sep, String... parts) { /* ... */ } // 必須+可変
Java

オーバーロードの意味をそろえる

同名メソッドは「同じ目的の異バリエーション」に限定し、戻り値の意味と副作用の有無を一致させます。名前は一貫性を持たせ、シグネチャ間で振る舞いが変わらないようにします。


オーバーロードとオーバーライドの違い

まったく別の概念

  • オーバーロード:同じクラス内で同名・異なる引数。コンパイル時に解決。
  • オーバーライド:サブクラスが親クラスのメソッドを「同じシグネチャ」で差し替える。実行時に動的ディスパッチ。
class Base { void show(String s) { System.out.println("Base:" + s); } }
class Sub extends Base { @Override void show(String s) { System.out.println("Sub:" + s); } }
// オーバーロードとは別。ここは引数同じで「振る舞いを差し替え」。
Java

両者の目的と解決タイミングを混同しないことが重要です。


実用例で身につける

例 1: 文字列連結のバリエーション

public class Joiner {
    static String join(String a, String b) {
        return a + b;
    }
    static String join(String a, String b, String c) {
        return a + b + c;
    }
    static String join(String... parts) {
        if (parts == null || parts.length == 0) return "";
        StringBuilder sb = new StringBuilder(parts[0]);
        for (int i = 1; i < parts.length; i++) sb.append(parts[i]);
        return sb.toString();
    }

    public static void main(String[] args) {
        System.out.println(join("A", "B"));         // AB
        System.out.println(join("A", "B", "C"));    // ABC
        System.out.println(join("J", "A", "V", "A"));// JAVA
    }
}
Java

例 2: 数値合計(型ごとに最適化)

public class Sum {
    static int sum(int a, int b) { return a + b; }
    static long sum(long a, long b) { return a + b; }
    static double sum(double a, double b) { return a + b; }

    public static void main(String[] args) {
        System.out.println(sum(3, 4));       // int
        System.out.println(sum(3L, 4L));     // long
        System.out.println(sum(2.5, 3.0));   // double
    }
}
Java

例 3: 入力源の違いを同名で受ける

import java.io.*;

public class ReaderUtil {
    static String readAll(String s) { return s; }
    static String readAll(File f) throws IOException {
        try (var br = new BufferedReader(new FileReader(f))) {
            var sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) sb.append(line).append('\n');
            return sb.toString();
        }
    }
    static String readAll(InputStream in) throws IOException {
        return new String(in.readAllBytes());
    }
}
Java

「読み取り」という同一目的を、入力源の違いでオーバーロードするのは典型パターンです。


設計の指針(重要部分のまとめ)

  • 同名メソッドは「同じ目的の異バリエーション」に限定し、戻り値と副作用の意味をそろえる。
  • 解決ルール(型一致→拡張→ボクシング→可変長)を意識し、曖昧になる設計を避ける。必要なら明示キャストで意図を確定。
  • 可変長引数は末尾に一つだけ。必須と任意を分けて、呼び出し側の意図が伝わるシグネチャに。
  • null で曖昧になる参照型のオーバーロードは注意。契約(許容するか、キャストを要求するか)を明示。
  • オーバーロード(コンパイル時解決)とオーバーライド(実行時解決)を混同しない。目的とタイミングが違う。

タイトルとURLをコピーしました