- ベストアンサー
オーバーロードの「あいまい」エラーについて
お世話になっております。 メソッドのオーバーロードにおいて、以下の様な場合にコンパイルエラーが発生します。 環境:JDK1.6.0_13 + eclipse3.3.2 public class Sample { static void meth(long... longs){ System.out.println("long..."); } static void meth(Integer... Integers) { System.out.println("Integer..."); } public static void main(String[] args){ meth(100); } } エラーメッセージ:メソッド meth(long[]) は型 Sample であいまいです (以下、「あいまいエラー」と表記します) 今回のケースでは、なぜこの様なエラーが出てしまうのか、今一つわからずに困っています。 「あいまいエラー」について少し調べを入れてみましたが、 参照型を引数に取るメソッドが複数ある時にnullを渡した時など、 明瞭にわかりやすいケースの例示は見つかったのですが、 今回の様なケースに当てはめて納得の行く情報ソースは見つけられませんでした。 まとめますと、私の欲しい情報は、 可変長引数リストを引数に取るオーバーロードメソッドが複数ある時に、 「あいまいエラー」が発生する規則です。 以上です。よろしくお願いします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
正確なことは分かりませんが、次のようなことかもしれません。 件の書籍によれば、先に書いた(a)(b)(c)で適合するメソッドを見つけた後は、「候補中のあるメソッドのパラメータの型が、候補中の他のメソッドのパラメータにすべて代入可能な場合には、その代入されるのが可能なメソッドは、限定度が低いので除外します。」という絞込みを行うよう書かれています。 Objectにはlong[]を代入可能なので、meth(Object... Objects) は除外されるのかもしれません。一方Numberにはlong[]を代入できません。 ただ、この考え方はメソッドのパラメータの型を配列と考えるかどうかが一貫していないので、見当違いかもしれません。 書籍の当該説明の所には「興味がある読者は、詳細について『Java言語仕様第3版』を調べてみてください」とあるので、そちらを見ると正確な挙動が分かるのかもしれませんが、私はその本を持っていないので確認できません。
その他の回答 (2)
- kenichiice
- ベストアンサー率72% (27/37)
書籍「プログラミング言語Java 第4版」の「9.6.1 正しいメソッドを見つける」に書いてある説明が参考になると思います。 それによれば、適合するメソッドの検索は (a) ボクシング変換と可変長引数を考慮せず検索 (b) ボクシング変換を考慮して検索 (c) ボクシング変換と可変長引数の両方を考慮して検索 の3段階で行われるとあります。 例のプログラムだと、(a)の段階でも(b)の段階でも適合するメソッドが見つからないので、(c)の検索が行われます。(c)の場合は meth(long... longs) と meth(Integer... Integers) の両方が適合します。 この後更にメソッドの絞込み処理が動くようですが、この例のケースではその絞込み処理では絞り込めず、結果的に両方のメソッドが候補として残ってしまい、「あいまいエラー」になるのだと思います。
お礼
ご回答ありがとうございます。 ご提示いただいた中の(c)の場合では、 複数のメソッドにマッチした際、それを一意に絞り込む明確な順序が定義されていない、という事になるのでしょうか。 meth(100)で質問文中のメソッドを呼ぼうとした時、 meth(long... longs)に対しては基本データ型の拡大変換⇒マッチ、 meth(Inetger... Integers)に対してはボックス変換してIS-Aチェック⇒マッチ。 両方がマッチしたけど、どちらを優先すべきかの順位が定義されていないから、これはあいまいになるよ。という事ですかね。 ただ不気味なのは、 meth(Integer... Integers)をmeth(Number... Numbers)に変更した場合、これは恐らく参照型の拡大変換によりマッチするがためにあいまいエラーになるのですが、 meth(Object... Objects)の時はコンパイル問題がなぜか解決されてしまうのです。 この辺は定義の甘い点なのか、例外的な動作として認識すべきものなのかはわかりませんが。 この辺りに関しても、もう少し調べを入れてみたいと思います。
- Tacosan
- ベストアンサー率23% (3656/15482)
少なくともこの例についていえば「int→long」と「int→Integer」の 2通りの変換ができることがエラーが原因かなぁ, という気はします. ただ, boxing/unboxing なんかの影響で非常に「非直感的」な仕様になっているような感じがします. たとえば 2つの meth はそのままで main の方で meth(new Integer(100)); と書いたら meth(Integer...) の方を呼び出してくれればいいのに, これでもエラーになっちゃうんだよね. meth(new Integer[]{100}); なら問題なく meth(Integer...) を呼び出すんだけど.... なんか変.
お礼
ご回答ありがとうございます。 「非直感的」まさにその通りだと思います。 シンタックスシュガーの弊害でしょうか。SE5.0からjavaの勉強を始めた私はことボックス化に関しては簡便なAPIに慣れすぎていて、 少し突っ込んだ所に触れるとすぐに思考停止してしまいます。 それでも、規則性さえはっきりと解明できれば気をつける事はできるので……。 なんとか突き止めたい所です。
お礼
ご回答ありがとうございます。 >件の書籍によれば、先に書いた(a)(b)(c)で適合するメソッドを見つけた後は、「候補中のあるメソッドのパラメータの型が、候補中の他のメソッドのパラメータにすべて代入可能な場合には、その代入されるのが可能なメソッドは、限定度が低いので除外します。」という絞込みを行うよう書かれています。 >Objectにはlong[]を代入可能なので、meth(Object... Objects) は除外されるのかもしれません。一方Numberにはlong[]を代入できません。 なるほど。定義された全てのメソッドの引数型を吸収する様な引数型のメソッドは複数マッチ時には除外されるのですね。 それはそれで非常に有用な情報です。ありがとうございます。 >書籍の当該説明の所には「興味がある読者は、詳細について『Java言語仕様第3版』を調べてみてください」とあるので、そちらを見ると正確な挙動が分かるのかもしれませんが、私はその本を持っていないので確認できません。 あたりを付けてくださってまことにありがとうございます。 折を見て購入してみようと思います。 自分はJavaの勉強を始めてから日が浅いため、今回の質問以外の部分でもわからない事が多いので、 そちらの本を一冊購入してもったいない事は無いと思いますし。 今回の様なAPI定義時に発覚せずPG実装時に問題が発覚するタイプのエラーは厄介ですが、 厳密な部分はともかくとして、トラブルを事前に回避する方法はわかったので、十分に必要な回答を得られたと判断します。 これで一旦の解決とさせていただきます。 以上です。ありがとうございました。