• ベストアンサー

オーバーロードの「あいまい」エラーについて

お世話になっております。 メソッドのオーバーロードにおいて、以下の様な場合にコンパイルエラーが発生します。 環境: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を渡した時など、 明瞭にわかりやすいケースの例示は見つかったのですが、 今回の様なケースに当てはめて納得の行く情報ソースは見つけられませんでした。 まとめますと、私の欲しい情報は、 可変長引数リストを引数に取るオーバーロードメソッドが複数ある時に、 「あいまいエラー」が発生する規則です。 以上です。よろしくお願いします。

  • Java
  • 回答数3
  • ありがとう数6

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

正確なことは分かりませんが、次のようなことかもしれません。 件の書籍によれば、先に書いた(a)(b)(c)で適合するメソッドを見つけた後は、「候補中のあるメソッドのパラメータの型が、候補中の他のメソッドのパラメータにすべて代入可能な場合には、その代入されるのが可能なメソッドは、限定度が低いので除外します。」という絞込みを行うよう書かれています。 Objectにはlong[]を代入可能なので、meth(Object... Objects) は除外されるのかもしれません。一方Numberにはlong[]を代入できません。 ただ、この考え方はメソッドのパラメータの型を配列と考えるかどうかが一貫していないので、見当違いかもしれません。 書籍の当該説明の所には「興味がある読者は、詳細について『Java言語仕様第3版』を調べてみてください」とあるので、そちらを見ると正確な挙動が分かるのかもしれませんが、私はその本を持っていないので確認できません。

参考URL:
http://www.amazon.co.jp/dp/4894717158
miyajima24
質問者

お礼

ご回答ありがとうございます。 >件の書籍によれば、先に書いた(a)(b)(c)で適合するメソッドを見つけた後は、「候補中のあるメソッドのパラメータの型が、候補中の他のメソッドのパラメータにすべて代入可能な場合には、その代入されるのが可能なメソッドは、限定度が低いので除外します。」という絞込みを行うよう書かれています。 >Objectにはlong[]を代入可能なので、meth(Object... Objects) は除外されるのかもしれません。一方Numberにはlong[]を代入できません。 なるほど。定義された全てのメソッドの引数型を吸収する様な引数型のメソッドは複数マッチ時には除外されるのですね。 それはそれで非常に有用な情報です。ありがとうございます。 >書籍の当該説明の所には「興味がある読者は、詳細について『Java言語仕様第3版』を調べてみてください」とあるので、そちらを見ると正確な挙動が分かるのかもしれませんが、私はその本を持っていないので確認できません。 あたりを付けてくださってまことにありがとうございます。 折を見て購入してみようと思います。 自分はJavaの勉強を始めてから日が浅いため、今回の質問以外の部分でもわからない事が多いので、 そちらの本を一冊購入してもったいない事は無いと思いますし。 今回の様なAPI定義時に発覚せずPG実装時に問題が発覚するタイプのエラーは厄介ですが、 厳密な部分はともかくとして、トラブルを事前に回避する方法はわかったので、十分に必要な回答を得られたと判断します。 これで一旦の解決とさせていただきます。 以上です。ありがとうございました。

その他の回答 (2)

回答No.2

書籍「プログラミング言語Java 第4版」の「9.6.1 正しいメソッドを見つける」に書いてある説明が参考になると思います。 それによれば、適合するメソッドの検索は (a) ボクシング変換と可変長引数を考慮せず検索 (b) ボクシング変換を考慮して検索 (c) ボクシング変換と可変長引数の両方を考慮して検索 の3段階で行われるとあります。 例のプログラムだと、(a)の段階でも(b)の段階でも適合するメソッドが見つからないので、(c)の検索が行われます。(c)の場合は meth(long... longs) と meth(Integer... Integers) の両方が適合します。 この後更にメソッドの絞込み処理が動くようですが、この例のケースではその絞込み処理では絞り込めず、結果的に両方のメソッドが候補として残ってしまい、「あいまいエラー」になるのだと思います。

参考URL:
http://www.amazon.co.jp/dp/4894717166
miyajima24
質問者

お礼

ご回答ありがとうございます。 ご提示いただいた中の(c)の場合では、 複数のメソッドにマッチした際、それを一意に絞り込む明確な順序が定義されていない、という事になるのでしょうか。 meth(100)で質問文中のメソッドを呼ぼうとした時、 meth(long... longs)に対しては基本データ型の拡大変換⇒マッチ、 meth(Inetger... Integers)に対してはボックス変換してIS-Aチェック⇒マッチ。 両方がマッチしたけど、どちらを優先すべきかの順位が定義されていないから、これはあいまいになるよ。という事ですかね。 ただ不気味なのは、 meth(Integer... Integers)をmeth(Number... Numbers)に変更した場合、これは恐らく参照型の拡大変換によりマッチするがためにあいまいエラーになるのですが、 meth(Object... Objects)の時はコンパイル問題がなぜか解決されてしまうのです。 この辺は定義の甘い点なのか、例外的な動作として認識すべきものなのかはわかりませんが。 この辺りに関しても、もう少し調べを入れてみたいと思います。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

少なくともこの例についていえば「int→long」と「int→Integer」の 2通りの変換ができることがエラーが原因かなぁ, という気はします. ただ, boxing/unboxing なんかの影響で非常に「非直感的」な仕様になっているような感じがします. たとえば 2つの meth はそのままで main の方で meth(new Integer(100)); と書いたら meth(Integer...) の方を呼び出してくれればいいのに, これでもエラーになっちゃうんだよね. meth(new Integer[]{100}); なら問題なく meth(Integer...) を呼び出すんだけど.... なんか変.

miyajima24
質問者

お礼

ご回答ありがとうございます。 「非直感的」まさにその通りだと思います。 シンタックスシュガーの弊害でしょうか。SE5.0からjavaの勉強を始めた私はことボックス化に関しては簡便なAPIに慣れすぎていて、 少し突っ込んだ所に触れるとすぐに思考停止してしまいます。 それでも、規則性さえはっきりと解明できれば気をつける事はできるので……。 なんとか突き止めたい所です。

関連するQ&A

  • オーバーロードで

    オーバーロードでメソッドgetvalueへコマンドライン引数から取得した値を渡したいのですが、どのようにすればいいのでしょうか。エラー:シンボルが見つけられません。 ×としたところでol.getvalue( args[i] );←ここに値をいれたいのですが、できません。なにか方法はありますでしょうか。 class OverLoad{     void getvalue(Boolean value){   System.out.println("Boolean型:" + value);     }     void getvalue(int value){   System.out.println("int型:" + value);     } public class Capsule{     public static void main(String[] args){   OverLoad ol = new OverLoad(); ×   ol.getvalue( args[i] ); ○   ol.getvalue(false); ○     ol.getvalue(80);     } }

  • 継承について

    以下のような問題(SJC-P試験)があり、 解説では考え方として ●メンバがフィールドなら「変数の型」 ●インスタンスメソッドなら「実際のオブジェクトの型」 ●クラスメソッドなら「変数の型」 とありました。 できればなぜこのような考え方(法則)になるか理解したいと思っています。 #当方、Javaプログラミング経験ゼロで、実際に下記のようなコーディングをするかどうかもわかりませんが、 #丸暗記だと実際のコーディングで使えそうにないので、できれば理解したいと思ってます。 下記問題は解説の考え方さえ丸暗記すれば解けるのかもしれませんが (なぜ解説のような考え方になるのか含め)教えていただけませんでしょうか。 ----- 【問題1】 class Super{  int d = 10;  void meth()System.out.println(d); } class Sub extends Super{  double d = 20.0;  void meth()System.out.println(d); } class Sample1{  public static void main(String[] args){  Super s = new Sub();  System.out.println(s.d);  s.meth(); } 【答え】 10 20.0 ----- 【問題2】 class Super{  static int d = 10;  static void meth()System.out.println(d); } class Sub extends Super{  static double d = 20.0;  static void meth()System.out.println(d); } class Sample2{  public static void main(String[] args){  Super s = new Sub();  System.out.println(s.d);  s.meth(); } 【答え】 10 10 ----- よろしくお願い致します。

    • ベストアンサー
    • Java
  • [Java1.5]Genericsとオーバーロード

    現在、Eclipseの上でJavaプログラミングを行っています。 ところが、オーバーロードを行う際にエラーとなり困っています。 疑問点と、解決策をお聞きできるとありがたく思います。 あるプログラムで、単純に言うと以下のようなオーバーロードを行いました。 public static String theFunction(Map<Integer, Integer> theMap){       ・・・ } public static String theFunction(Map<Integer, String> theMap){       ・・・ } すると、一つ目のメソッドに対し Duplicate method theFunction(Map<Integer, Integer> theMap) in ... 二つ目のメソッドに対し Duplicate method theFunction(Map<Integer, String> theMap) in ... というエラーが出てしまいました。 こういうものなのでしょうか? つまり、同じ型のGenericsは、その要素の型が違っていても同一視されるのでしょうか。 またその場合、代替策は無いでしょうか? つまり、 theFunction(x); とした時、x が Map<Integer, Integer> か Map<Integer, String> かによって処理を変える良い方法は無いでしょうか? よろしくお願い致します。

    • ベストアンサー
    • Java
  • Integerについて

    class Sample5_7_Integer { /** * Integerクラスのメソッド */ public static void main(String[] args) { //String → int int i1 = Integer.parseInt(args[0]); //int型にすることにより計算可能 System.out.println(i1 + 100); //String → integer Integer i2 = Integer.valueOf(args[0]); System.out.println(i2); Integer i3 = new Integer(100); System.out.println(i2.equals(i3)); } } をEclipseで実行したところ、 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 at benkyou.Sample5_7_Integer.main(Sample5_7_Integer.java:10) というエラーになってしまいます。 どなたか解決法をお願いします。

    • ベストアンサー
    • Java
  • Java何故エラーになるのですか?

    public class Sample3_1 { public static void notMain(String[] args) { System.out.println("not main"); } public static void main (String[] args) { System.out.println("こんにちは、Java"); System.out.println("私の名前は、コウゾウです。"); } } Exception in thread "main" java.lang.Error: Unresolved compilation problems: トークン "Invalid Character" に構文エラーがあります。このトークンを削除してください 構文エラーがあります。"}" を挿入して ClassBody を完了してください at Sample3_1.main(Sample3_1.java:10) "}" を挿入して」と書かれてますが、 "}" には間違いなさそうです。 どなたか解説のほどを宜しくお願い致します。

    • ベストアンサー
    • Java
  • どこにエラーがあるのでしょうか?

    public class Sample6_2 { public static void main(String[] args) { int probabilityOfRain = 20; if (30 <= probabilityOfRain) System.out.println("傘を持っていく");            System.out.println("傘を持っていく"); if (probabilityOfRain < 30) { System.out.println("傘を持って行かない");     System.out.println("傘を持って行かない"); } } } Exception in thread "main" java.lang.Error: Unresolved compilation problems: トークンに構文エラーがあります。これらのトークンを削除してください トークンに構文エラーがあります。これらのトークンを削除してください at Sample6_2.main(Sample6_2.java:8) と出ました。度々すいません。 どこにエラーがあるのでしょうか?

    • ベストアンサー
    • Java
  • コンストラクタのオーバーロードについて

    class loo{ //フィールドの定義 int sland; //コンストラクタの定義1 loo(){ this.sland = 28; } //コンストラクタの定義2 loo(int sland){ this.sland = sland; } //メソッドの定義 void ken(){ System.out.println(this.sland); } } //mainメソッド class kkk{ public static void main(String args[]){ ---------------------------------------------- loo lo = new loo(); lo.ken(); lo.ken(100); ---------------------------------------------- } } コンストラクタのオーバーロードについて、伺いたいことがありますので掲載致しました。 今回は、kenメソッドを用いて変数slandに入っている値を表示するプログラムを作りたいと思っています。 コンストラクタのオーバーロードを利用するわけですが、プログラム実行後に 28 100 という風な出力結果を得ようと、上記のようなプログラミングを実施しました。 しかし、いざコンパイルをかけると java:27: ken() (loo 内) を (int) に適用できません lo.ken(100); ~ というエラーが表示されてしまいます。 ----でかっこってある部分に問題があるのはわかっているのですが、思うように結果を得ることができない状況です。 また、----の部分を、 loo lo = new loo(100); lo.ken(); lo.ken(); と、書き換えると出力結果は 100 100 と表示され、28が表示されなくなってしまいます。 お手数ですが、ご教授の程お願い致します。

  • abstract と static を一緒に付けることはある?

    抽象クラスの抽象メソッドにstaticを付ける(abstract と static をメソッドに一緒に付ける)ことはありますか? 例えば、 abstract class Super {  static abstract void meth(); } class Sub extends Super {  static void meth() {   System.out.print("hello");  } } として、mainの中に  Sub.meth(); を書いてみたのですが、普通にコンパイルは通りhelloが出力されます。 staticの意味を考えると、こういうことをするのは意味がないと思うのですが、独学なので身近に聞ける人もいません。 御教授よろしくお願いします。

  • コンパイルエラーが解決できません

    Java初心者です。サンプルコードを実行しながら勉強しているのですが以下のプログラムを実行するとコンパイルエラーになってしまいます。 バージョンはJ2SE5.0です。 //列挙型サンプルプログラム public class Sample3_4 { public enum Dept {KOKUGO, SHAKAI, SANSU, RIKA} public static void main(String[] args) { System.out.println("-------- 特定要素の取り出し ----------"); Dept d1 = Dept.SANSU; System.out.println(d1); System.out.println("-------- 全要素の取り出し ----------"); Dept[] d = Dept.values(); for(int i = 0; i < d.length; i++); System.out.println(d[i]); //上記の3行は以下と置き換えることができる //for(Dept d: Dept.values()); //System.out.println(d); System.out.println("-------- switch 文での利用 ----------"); System.out.println("算数は" + course(Dept.SANSU)); } public static String coures(Dept d) { switch(d) { case KOKUGO: case SHAKAI: return "文系"; case SANSU: case RIKA: return "理系"; default: throw new AssertionError(d + "はありません"); } } } ・エラー内容 Sample3_4.java:13:シンボルを見つけられません。 シンボル:変数i 場所 :Sample3_4 の クラス System.out.println(d[i]); Sample3_4.java:20:シンボルを見つけられません。 シンボル:メソッド course(Sample3_4.Dept) 場所 :Sample3_4 の クラス System.out.println("算数は" + course(Dept.SANSU)) 環境変数などを調べてPathを追加してみたりしたのですが、うまくいきません。エラーの原因はどこにあると考えられるのでしょうか?

    • ベストアンサー
    • Java
  • newの基本的な使い方が理解できていません

    以下のソースコードで【Super s = new Sub();】となっているのですが、これはSuperを見ているのでしょうか?またはSubでしょうか? この考え方がいまいち理解できません。 次の【System.out.println(s.d);】では、class Superの10を返しているようですが、その次の行でのs.meth(); ではclass Subの20を返しているようです。 また、クラスsuperのint dおよび、boid meth()をstaticにすると、そちらをみているようなのですが、混乱して理解できません。 すみませんが、どのようになっているか教えて頂けませんでしょうか? class Super{ int d = 10; void meth(){ System.out.println(d); } } class Sub extends Super{ double d =20.0; void math (){ System.out.println(d); } } class Test{ public static void main(String args[]){ Super s = new Sub(); System.out.println(s.d); s.meth(); } }

    • ベストアンサー
    • Java