オーバーロードを理解する

オーバーロードは、引数の型や個数が異なる同名メソッドを用意する仕組みです。コンパイル時に呼出し先を選びます。名前だけ、戻り値だけ、実行時のオブジェクトだけで選ぶのではありません。

この単元で学ぶこと

  • 同名宣言の合法性を判定する
  • 引数の型と個数から選択されるメソッドを求める
  • 曖昧な呼出しを識別する

本文解説

名前が同じでも引数が違う static String f(int n){return "I";}とstatic String f(String s){return "S";}を同じクラスへ宣言できます。f(1)はI、f("1")はSです。リテラルの見た目が似ていても、1はint、"1"はStringという型の違いで選びます。

個数と型の順序 f(int)とf(int,int)は引数の個数が違い、f(int,String)とf(String,int)は型の順序が違うので区別できます。仮引数の名前だけを変えたf(int a)とf(int b)は同じシグネチャであり重複宣言です。シグネチャの判定に仮引数名は使いません。

戻り値だけでは区別不可 static int f(int n)とstatic long f(int n)は戻り値が違っても同時に宣言できません。int x=f(1)と書いたからint版を選ぶ、という解決はしません。戻り値やアクセス修飾子だけを変えてもオーバーロードになりません。

一致と拡大変換 f(int)とf(long)があれば、intの1はint版、longの1Lはlong版です。byte変数を渡す場合は両方へ拡大できますが、より限定的なint版が選ばれます。f(long)だけならintを拡大して呼べます。intからbyteへの暗黙の縮小はメソッド呼出し変換では行いません。

参照型と静的な型 f(Object)とf(String)がある場合、f("x")はString版です。しかしObject x="x";f(x)では実引数式xの静的な型Objectを基にObject版を選びます。実行時の動的束縛でオーバーライド実装を決める話とは段階が異なります。

nullと曖昧さ f(Object)とf(String)にnullを渡すと、より限定的なString版を選びます。一方f(String)とf(Integer)ではどちらもnullを受け取れ、互いに片方が部分型ではないためf(null)は曖昧です。明示的に(String)nullとすればString版へ限定できます。

変換の段階 Javaはまず厳密な呼出し変換で適用できるメソッドを探し、次にボクシング等を許す段階、最後に可変長引数の段階を検討します。f(long)とf(Integer)へintを渡す場合は、拡大変換で呼べるlong版が先の段階で見つかります。単純に引数の見た目が近いほうを選ぶ規則ではありません。

候補表で確認 各宣言の引数型、実引数式の静的な型、必要な変換を表にします。適用できない候補を除き、残る候補間の優先順位を確認します。曖昧な例と同一シグネチャの重複例は別の原因なので、コンパイラの診断も区別して読みます。

図解

呼出し先を決める順序
戻り値だけが異なる重複宣言は、呼出しを考える前に不正。

重要ポイント

  • 型・個数・型の順序で同名宣言を区別する。
  • 戻り値型や仮引数名だけでは区別できない。
  • 選択は実引数式の静的な型を使う。
  • 複数候補で一意に決まらなければコンパイルエラー。

間違えやすい点

  • 戻り値を受ける変数の型で宣言重複を解決できると思わない。
  • nullがどんな同名宣言でも一意に決まると考えない。
  • オーバーロードとオーバーライドを混同しない。

用語解説

オーバーロード
引数の型などが異なる同名メソッドを用意すること。
シグネチャ
ここでは名前と仮引数の型の列など、宣言を区別する情報。
静的な型
コンパイル時に式に与えられる型。
曖昧な呼出し
適用できる候補から一つを選べない呼出し。

関連教材

参考資料

教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。

確認問題の出題・採点や学習履歴の保存にはログインが必要です。