オーバーロード解決

このレッスンでは、同じ名前のメソッドが複数あるときに、どの署名が呼ばれるのかを特定できるようになります。

まず予測してください

static String pick(long x) { return "long"; } static String pick(Integer x) { return "Integer"; } static String pick(Object x) { return "Object"; } static String pick(int... x) { return "varargs"; } int n = 5; System.out.println(pick(n));

候補は4つあります。どれが呼ばれるでしょうか。答えは long です。

コンパイラは3段階で候補をふるいにかける

オーバーロードの解決は実行時ではなくコンパイル時に決まります。しかも一度に全候補を比べるのではなく、次の順で段階的に探します。

  1. 第1段階 — ボクシングも可変長引数も使わずに呼べる候補だけを見る。ここで見つかれば確定
  2. 第2段階 — 第1段階で見つからなければ、ボクシングとアンボクシングを許して探す
  3. 第3段階 — それでも見つからなければ、可変長引数を許して探す

先ほどの pick(n) では、第1段階で int から long への拡大変換だけで呼べる pick(long) が見つかります。だから pick(Integer)pick(int...) も検討されません。拡大変換はボクシングより強く、ボクシングは可変長引数より強い、と覚えてください。

段階ごとの結果を並べる

同じ4つの候補に、いろいろな引数を渡した結果です。

呼び出し選ばれる署名理由
pick(5)pick(long)第1段階の拡大変換で決着
pick((short) 5)pick(long)short も long へ拡大できる
pick(Integer.valueOf(5))pick(Integer)完全一致が最優先
pick(5, 5)pick(int...)引数2個で呼べるのはこれだけ

3行目に注意してください。IntegerObject へも渡せるので第1段階で2つの候補が残りますが、そのときはより限定的な型が勝ちます。IntegerObject の一種なので Integer のほうが限定的です。

同点になるとコンパイルエラー

f(int, long)f(long, int) の2つに f(5, 5) を渡すと、どちらも同じ強さで決着しません。この場合は「あいまいな参照」としてコンパイルエラーになります。試験ではこの形も出るので、候補が横並びになっていないかを確かめる癖をつけてください。

演習で確かめます

4種類の引数で pick を呼び、選ばれた署名の名前を順につないで返します。予想を紙に書いてから実行してください。

要件

  1. resolve は pick を 4 回呼び、その戻り値をカンマ区切りでつないで返すこと
  2. 呼ぶ順は int, short, Integer, 引数2個 の順にすること
  3. pick の 4 つの定義は書き換えないこと

入出力例

resolve(5)"long,long,Integer,varargs" resolve(100)"long,long,Integer,varargs" resolve(0)"long,long,Integer,varargs"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.java
学習モード

メモ

オーバーロード解決

⌘S で保存