0Pricing
Java Academy · レッスン

メソッドオーバーロードの規則

Java がオーバーロードされたメソッドを解決する仕組みと、よくある曖昧性の問題を理解します。

「メソッドオーバーロードの規則」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

メソッドオーバーロードの規則

メソッドのオーバーロードを使うと、同じ名前でパラメーターリストが異なる複数のメソッドを定義できます。Javaは正確な解決規則を使い、コンパイル時に最適なメソッドを選択します。

オーバーロードとは

オーバーロードされたメソッドは同じ名前を持ちますが、パラメーターの数、型、または順序が異なります。戻り値の型だけではオーバーロードとして十分ではありません。

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; }

    // compile error — same signature, different return type only:
    // long add(int a, int b) { return a + b; }
}

Calculator calc = new Calculator();
System.out.println(calc.add(1, 2));       // 3 (int)
System.out.println(calc.add(1.5, 2.5));   // 4.0 (double)
System.out.println(calc.add(1, 2, 3));    // 6 (3-arg)

解決:最も具体的な一致

Javaは適用可能なメソッドの中から、最も具体的なものを選択します。拡大変換、オートボクシング、可変長引数は、優先順位に従って試されます。

static void print(int x)    { System.out.println("int: "    + x); }
static void print(long x)   { System.out.println("long: "   + x); }
static void print(Object x) { System.out.println("Object: " + x); }

print(42);       // int: 42 (exact match — most specific)
print(42L);      // long: 42 (exact match)
print(3.14);     // Object: 3.14 (no float match, widening then autoboxing)

オートボクシングより拡大変換を優先

Javaは、プリミティブ型をラッパー型へオートボクシングするより、プリミティブ型の拡大変換を優先します。そのため、意外な結果になることがあります。

static void display(long n)    { System.out.println("long: " + n); }
static void display(Integer n) { System.out.println("Integer: " + n); }

int x = 100;
display(x); // long: 100 — widens int to long BEFORE autoboxing to Integer
// This surprises many developers!

static void show(Long n)    { System.out.println("Long"); }
static void show(Integer n) { System.out.println("Integer"); }

// show(100); // compile error — ambiguous! Neither is more specific

null引数によるあいまいさ

複数のメソッドが参照型を受け取れる場合、オーバーロードされたメソッドにnullを渡すとあいまいになることがあります。nullをキャストして解決してください。

static void handle(String s)  { System.out.println("String: " + s); }
static void handle(Integer i) { System.out.println("Integer: " + i); }
static void handle(Object o)  { System.out.println("Object"); }

handle((String) null);  // String: null (cast resolves ambiguity)
handle((Integer) null); // Integer: null
// handle(null);        // compile error: ambiguous (String vs Integer)

継承とオーバーロード

メソッドの解決では、実行時の型ではなく参照変数の宣言型が考慮されます。これはコンパイル時に決まります。

class Animal {}
class Dog extends Animal {}

static void greet(Animal a) { System.out.println("Animal"); }
static void greet(Dog d)    { System.out.println("Dog"); }

Animal a = new Dog(); // declared as Animal
greet(a);   // Animal — compile-time type is Animal!

Dog d = new Dog();
greet(d);   // Dog — compile-time type is Dog

オーバーロードとオーバーライド

オーバーロードはコンパイル時の決定(静的ディスパッチ)です。オーバーライドは実際のオブジェクト型に基づく実行時の決定(動的ディスパッチ)です。

class Base {
    void run() { System.out.println("Base.run"); }
}
class Sub extends Base {
    @Override
    void run() { System.out.println("Sub.run"); } // overriding

    void run(int speed) { System.out.println("Sub.run(" + speed + ")"); } // overloading
}

Base b = new Sub();
b.run();     // Sub.run — override (runtime dispatch)
// b.run(10); // compile error — Base doesn't have run(int)

オーバーロードの一般的なパターン

APIでのオーバーロードの一般的な用途は、すべてのパラメーターを受け取るメソッドに委譲する便利なメソッドを提供することです。

class Connection {
    void connect(String host, int port, int timeout) {
        System.out.println("Connecting to " + host + ":" + port + " timeout=" + timeout);
    }

    // Convenience overloads
    void connect(String host, int port) {
        connect(host, port, 30); // delegate with default timeout
    }

    void connect(String host) {
        connect(host, 5432); // delegate with default port
    }
}

new Connection().connect("db.example.com");
// Connecting to db.example.com:5432 timeout=30

オーバーロードとジェネリクス

ジェネリックメソッドのオーバーロードには注意が必要です。型消去によって、異なるように見える2つのシグネチャがコンパイル後に同一になることがあります。

// Type erasure problem: both methods erase to the same signature!
// static void process(List<String> list) {} // compile error
// static void process(List<Integer> list) {} // duplicate after erasure

// Solutions:
// 1. Use different method names: processStrings / processIntegers
// 2. Use a generic method with bounded type:
static <T extends Number> void processNumbers(List<T> list) {
    list.forEach(n -> System.out.println(n.doubleValue()));
}
processNumbers(List.of(1, 2, 3));
processNumbers(List.of(1.5, 2.5));

実践:Builderスタイルのオーバーロード

柔軟なオブジェクト生成を提供するため、BuilderやファクトリのAPIではオーバーロードがよく使われます。

class Notification {
    final String title, body;
    final String imageUrl;
    final boolean urgent;

    // Factory overloads for convenience
    static Notification simple(String title, String body) {
        return new Notification(title, body, null, false);
    }
    static Notification urgent(String title, String body) {
        return new Notification(title, body, null, true);
    }
    static Notification withImage(String title, String body, String url) {
        return new Notification(title, body, url, false);
    }
    Notification(String title, String body, String imageUrl, boolean urgent) {
        this.title = title; this.body = body;
        this.imageUrl = imageUrl; this.urgent = urgent;
    }
}

オーバーロードの落とし穴

次のような、オーバーロードに関するよくある誤りを避けてください:

  • 同じ操作に対するオーバーロードが多すぎる場合は、代わりにBuilderを使用します
  • パラメーターの順序だけが異なるオーバーロードは、混乱を招きます
  • 意外な拡大変換:intがIntegerではなくlongに解決されることがあります
// Confusing: order-based overloads
// void save(String name, int age)  {}
// void save(int age, String name)  {} // very confusing!

// Better: use a record/DTO
record UserData(String name, int age) {}
void save(UserData data) {}

// Surprising widening
static void m(long x)   { System.out.println("long"); }
static void m(Integer x){ System.out.println("Integer"); }
int v = 5;
m(v); // long! widening preferred over autoboxing

理解度チェック

long型とInteger型のパラメータでオーバーロードされたメソッドにint型の引数を渡した場合、どちらが選択されますか?

まとめ:メソッドオーバーロードのルール

重要なポイント:

  • オーバーロードはパラメータの個数、型、または順序で区別されます。戻り値の型だけでは区別されません
  • Javaは引数の宣言型を使って、コンパイル時にオーバーロードを解決します
  • プリミティブ型をラッパー型へオートボクシングするより、プリミティブ型の拡大変換が優先されます
  • null引数はあいまいさを引き起こす場合があります。キャストして解決します:handle((String) null)
  • オーバーロードはコンパイル時、オーバーライドは実行時に解決されるため、異なる仕組みです
  • 完全なパラメータを持つ中心的なメソッドに委譲する、利便性のためのオーバーロードを使用します

よくある質問

「メソッドオーバーロードの規則」レッスンは無料ですか?

はい。「メソッドオーバーロードの規則」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「メソッドオーバーロードの規則」で何を学びますか?

Java がオーバーロードされたメソッドを解決する仕組みと、よくある曖昧性の問題を理解します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「メソッドオーバーロードの規則」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. メソッドオーバーロードの規則
  2. 可変長引数パラメーター
  3. static フィールドと定数
  4. ユーティリティクラスと static ファクトリーメソッド
← Java Academyに戻る