あなたの最初のケースはかなり簡単です。以下の方法:
public MyContainer<IntWrapper> pack(int key, Object[] values)
は引数 - に完全に一致します(1, String[])
。JLS セクション 15.12.2から:
最初のフェーズ (§15.12.2.2) は、ボックス化またはボックス化解除の変換を許可せずにオーバーロードの解決を実行します。
これで、これらのパラメーターを 2 番目のメソッドに渡す際に、ボクシングは必要ありません。Object[]
のスーパータイプString[]
です。String[]
パラメータに引数を渡すことObject[]
は、Java 5 より前でも有効な呼び出しでした。
コンパイラは、2番目のケースでトリックをしているようです:
2 番目のケースでは、var-args を使用したため、その JLS セクションで説明されている 3 番目のフェーズに従って、var-args とボックス化またはボックス化解除の両方を使用して、メソッドのオーバーロードの解決が行われます。
第 3 フェーズ (§15.12.2.4) では、オーバーロードを可変アリティ メソッド、ボックス化、およびボックス化解除と組み合わせることができます。
var-argsを使用しているため、ここでは 2 番目のフェーズは適用されないことに注意してください。
2 番目のフェーズ (§15.12.2.3) では、ボックス化とボックス化解除を許可しながらオーバーロードの解決を実行しますが、可変アリティ メソッドの呼び出しは引き続き使用できません。
ここで起こっているのは、コンパイラが型引数を正しく推論していないことです* (実際には、型パラメータが仮パラメータとして使用されているため、正しく推論しています。この回答の最後にある更新を参照してください)。したがって、メソッド呼び出しの場合:
MyContainer<IntWrapper> test = converter.pack(1, "Test", "Test2");
コンパイラはK
、ジェネリック メソッドの の型をIntWrapper
LHS から と推測する必要がありました。しかし、タイプであると推測K
しているようです。そのため、Integer
両方のメソッドがこのメソッド呼び出しに等しく適用できるようになりました。var-args
boxing
ただし、そのメソッドの結果が何らかの参照に割り当てられていない場合、この場合のようにコンパイラが適切な型を推測できないことを理解できます。あいまいなエラーを与えることは完全に許容されます。
converter.pack(1, "Test", "Test2");
たぶん、一貫性を維持するために、最初のケースではあいまいとマークされています。しかし、JLSからの信頼できる情報源や、この問題について言及している他の公式の参考文献が見つからなかったため、やはりよくわかりません。検索を続けます。見つけたら、答えを更新します。
明示的な型情報でコンパイラをだましましょう。
メソッド呼び出しを変更して、明示的な型情報を提供する場合:
MyContainer<IntWrapper> test = converter.<IntWrapper>pack(1, "Test", "Test2");
これで、型K
は と推測されますIntWrapper
が、1
は に変換できないためIntWrapper
、そのメソッドは破棄され、2 番目のメソッドが呼び出され、完全に正常に動作します。
率直に言って、ここで何が起こっているのか本当にわかりません。最初のケースでも、次の問題で機能するため、コンパイラがメソッド呼び出しコンテキストから型パラメーターを推測することを期待します。
public static <T> HashSet<T> create(int size) {
return new HashSet<T>(size);
}
// Type inferred as `Integer`, from LHS.
HashSet<Integer> hi = create(10);
しかし、この場合はそうではありません。したがって、これはバグである可能性があります。
*または、型が引数として渡されない場合に、コンパイラが型引数を推測する方法を正確に理解していない可能性があります。したがって、これについてさらに学習するために、JLS §15.12.2.7およびJLS §15.12.2.8を試してみました。これは、コンパイラが型引数を推測する方法に関するものですが、それは私の頭の中で完全に進んでいます。
したがって、今のところはそれを受け入れて、別の方法 (明示的な型引数を提供する) を使用する必要があります。
結局のところ、Compiler は何のトリックもしていませんでした。
@zhong.j.yu. のコメントで最終的に説明されているように、コンパイラは、15.12.2.7 セクションに従って推論に失敗した場合に、型推論にセクション 15.12.2.8 のみを適用します。ただし、ここでは、Integer
渡された引数から型を推測できます。これは、明らかに型パラメーターがメソッドの形式パラメーターであるためです。
したがって、はい、コンパイラは型を as として正しく推論するInteger
ため、あいまいさは有効です。そして今、この答えは完成したと思います。