オーバーロードを理解する
オーバーロードは、引数の型や個数が異なる同名メソッドを用意する仕組みです。コンパイル時に呼出し先を選びます。名前だけ、戻り値だけ、実行時のオブジェクトだけで選ぶのではありません。
この単元で学ぶこと
- 同名宣言の合法性を判定する
- 引数の型と個数から選択されるメソッドを求める
- 曖昧な呼出しを識別する
本文解説
名前が同じでも引数が違う 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がどんな同名宣言でも一意に決まると考えない。
- オーバーロードとオーバーライドを混同しない。
用語解説
- オーバーロード
- 引数の型などが異なる同名メソッドを用意すること。
- シグネチャ
- ここでは名前と仮引数の型の列など、宣言を区別する情報。
- 静的な型
- コンパイル時に式に与えられる型。
- 曖昧な呼出し
- 適用できる候補から一つを選べない呼出し。
関連教材
参考資料
教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。
確認問題の出題・採点や学習履歴の保存にはログインが必要です。