Java でオートボクシングによって一部の呼び出しがあいまいになるのはなぜですか?

StackOverflow https://stackoverflow.com/questions/501412

質問

今日、自動ボックス化によりメソッドのオーバーロードの解決が曖昧になる場合があることに気づきました。最も単純な例は次のようになります。

public class Test {
    static void f(Object a, boolean b) {}
    static void f(Object a, Object b) {}

    static void m(int a, boolean b) { f(a,b); }
}

コンパイルすると、次のエラーが発生します。

Test.java:5: reference to f is ambiguous, both method
    f(java.lang.Object,boolean) in Test and method
    f(java.lang.Object,java.lang.Object) in Test match

static void m(int a, boolean b) { f(a, b); }
                                  ^

このエラーの修正は簡単です。明示的なオートボクシングを使用するだけです。

static void m(int a, boolean b) { f((Object)a, b); }

これにより、最初のオーバーロードが期待どおりに正しく呼び出されます。

では、なぜオーバーロードの解決は失敗したのでしょうか?なぜコンパイラは最初の引数を自動ボックス化せず、2 番目の引数を通常どおり受け入れなかったのでしょうか?なぜ明示的に自動ボックス化を要求する必要があったのでしょうか?

役に立ちましたか?

解決

あなた自身をオブジェクトへの最初の引数をキャストすると、

、コンパイラはオートボクシングを使用しない方法と一致します(JLS3 15.12.2):

  

第一段階は、(§15.12.2.2)を行います   許可のないオーバーロードの解決   ボクシングまたはアンボクシング変換、または   変数アリティメソッドの使用   呼び出し。該当の方法はされていない場合   その後、このフェーズ中に見つかりました   処理は、第二に進み   相ます。

あなたが明示的にキャストしていない場合は、

、それはオートボクシングを許可する、マッチング方法を見つけようとの第二段階に行きます、そして、あなたの第2引数はブールまたはオブジェクトで一致させることができるので、それは、実に曖昧です。

  

第二相は、(§15.12.2.3)を行います   オーバーロードの解決可能にしながら、   ボクシングとアンボクシングが、それでも   変数アリティの使用を妨げます   メソッド呼び出します。

ブール引数のないオートボクシングは必要ありませんので、

なぜ、第二段階では、コンパイラは、第二の方法を選択していないのですか?それは、2マッチング方法を発見した後、唯一のサブタイプの変換に関係なく最初の場所でそれらを一致するように行われた任意のボクシングまたはアンボクシングの二つの最も具体的な方法を決定するために使用されているので(§15.12.2.5)。

また:コンパイラは常に必要なオート(アン)ボクシングの数に基づいて、最も具体的な方法を選択することができません。それはまだあいまいな例になることができます。たとえば、これはまだ曖昧です。

public class Test {
    static void f(Object a, boolean b) {}
    static void f(int a, Object b) {}

    static void m(int a, boolean b) { f(a, b); } // ambiguous
}

は、マッチング法(コンパイル時にステップ2)を選択するためのアルゴリズムはJLSに固定され、説明されていることに注意してください。一度フェーズ2には、選択的オートボクシングまたはアンボクシングはありません。コンパイラは、アクセス可能(これらのケースでは、両方の方法)および適用されるのすべてのの方法(再び二つの方法)を見つけ、とだけにしてある、ボクシング/アンボクシングを見ずに、最も具体的なものを選択しますここでは、あいまいな。

他のヒント

あなたが言う時 f(a, b)、コンパイラはどの関数を参照すべきか混乱します。

それの訳は ある です 整数, 、ただし、期待される引数は f オブジェクトです。したがって、コンパイラは変換することを決定します ある オブジェクトに。さて問題は、次の場合です。 ある オブジェクトに変換できるので、 b.

これは、関数呼び出しがどちらの定義も参照できることを意味します。これにより、呼び出しが曖昧になります。

変換するとき ある 手動でオブジェクトにアクセスすると、コンパイラは最も近い一致を検索してそれを参照するだけです。

コンパイラが「ボクシング/ボクシング変換の最小数を実行することで到達できる関数を選択しなかったのはなぜですか?

次のケースを参照してください。

f(boolean a, Object b)
f(Object a , boolean b)

みたいに電話したら f(ブール値 a, ブール値 b), 、どの機能を選択すればよいでしょうか?曖昧ですよね?同様に、多くの引数が存在する場合、これはより複雑になります。そのため、コンパイラは代わりに警告を表示することを選択しました。

プログラマが実際に呼び出すつもりだった関数を知る方法がないため、コンパイラはエラーを返します。

  

なぜオーバーロードの解決をしました   不合格?なぜコンパイラの自動ボックスませんでした   最初の引数、および受け入れ   通常、第二引数?なぜ私がやりました   オートボクシングを要求しなければなりません   明示的に?

これは、通常、第二引数を受け入れませんでした。 「ブール」はあまりにもオブジェクトに箱詰めすることができることを覚えておいてください。あなたが明示的に持っているだけでなくObjectにブール引数をキャストし、それが働いていた可能性があります。

//java.sun:

のhttpを参照してください。 COM /ドキュメント/書籍/ JLS / third_edition / HTML / expressions.html#20448

その後、何のボクシングを呼び出すための方法を見つける必要がありませんので、

キャストが役立ちます。キャストせずに2回目の試行は、ボクシングをできるようにすることです、その後もブール値を箱詰めすることができます。

人々は推測にするよりも、何が起こるか言うことをはっきりと理解できるスペックを持っている方が良いです。

Javaコンパイラは段階でオーバーロードされたメソッドとコンストラクタを解決します。第一相[§15.12.2.2]には、[§4.10]サブタイプによって適用可能な方法を特定します。 int型はObjectのサブタイプではないので、この例で、どちらの方法が、適用されます。

第二相[§15.12.2.3]で、コンパイラは、オートボクシングとサブタイプの組み合わせであるメソッド呼出し変換[§5.3]によって適用可能な方法を特定します。 int引数は、両方のオーバーロードのために、オブジェクトのサブタイプである整数に変換することができます。ブール引数は、最初の過負荷のための変換を必要としない、そして第二のために、ブール、オブジェクトのサブタイプに変換することができます。したがって、両方の方法は、第二段階において適用可能である。

複数の方法が適用可能であるので、

、コンパイラは[§15.12.2.5]最も特異的であるかを決定しなければなりません。これは、パラメータの型ではなく、引数の型を比較し、それが彼らをAutoBoxのはありません。オブジェクトとブールは無関係なタイプなので、同じように、特定の考えられています。どちらの方法は、他のより特異的であるので、メソッド呼び出しはあいまいである。

あいまいさを解決する一つの方法は、オブジェクトのサブタイプであるブールを入力するブール・パラメータを変更することです。最初のオーバーロードは、常に秒以上(該当する場合)、より具体的になります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top