2013-02-01 9 views
11

次のサンプルでは、​​Foo.create()の最初の呼び出しの汎用引数をFoo.test()に推測することはできますが、2番目の呼び出しではできません。私は javacが引数として使用する関数の汎用型引数を推論できないのはなぜですか?

public class Nonsense { 
    public static class Bar { 
     private static void func(Foo<String> arg) { } 
    } 

    public static class Foo<T> { 

     public static <T> Foo<T> create() { 
      return new Foo<T>(); 
     } 

     private static void test() { 
      Foo<String> foo2 = Foo.create(); // compiles 
      Bar.func(Foo.create());   // won't compile 
      Bar.func(Foo.<String>create()); // fixes the prev line 
     } 
    } 
} 

(コンパイルエラーがタイプNonsense.BarのメソッドFUNC(Nonsense.Foo)は引数(Nonsense.Foo)には適用されませんである)は、Java 6

を使用しています。

注:私は、test()の3行目で修正できますが、コンパイラのエラーは、コンパイラがその型を推論できないような特定の制限があるかどうか不思議です。それはのように私にはここにそれのための十分な文脈があると私にはが表示されます。

+4

"それは十分スマートではありません。" –

+0

@ルイス -​​ それは十分にスマートにすることはできませんが、私はまだ、理由を考え出していないと考えられます。 – bacar

+0

@bacar:それはおそらく十分にスマートになる可能性があります。 –

答えて

14

を仕様に40ページが含まれ、メソッドのオーバーロードの解決は、あなたが呼び出しているメソッドから任意のターゲット・タイプ情報の前に進まなければなりませんは、funcの宣言に型変数Tを推論しようとするために考慮に入れることができます。この場合、funcという名前のメソッドが1つしかないことがわかりますが、JLSが義務付けているのはJava 7のjavacの動作です。

コンパイルは次のように実行されます。まず、コンパイラは、funcという名前のClass Barの静的メソッドへの呼び出しをコンパイルしているとみなします。オーバーロードの解決を行うには、メソッドが呼び出されているパラメータを調べる必要があります。これは些細なケースであるにもかかわらず、やはりそうする必要があり、そうするまで、それを助けるために利用できる方法の正式なパラメータに関する情報はありません。実際のパラメータは、1つの引数、を返すと宣言されたFoo.create()への呼び出しで構成されます。この場合も、ターゲットメソッドの基準がないため、返されるデータ型がFoo<T>のイレーズ(Foo<Object>)であることが推測できます。

funcのオーバーロードのいずれも実際のパラメータFoo<Object>と互換性がなく、エラーが発生するため、メソッドオーバーロードの解決に失敗します。

これはもちろん、メソッド呼び出しのターゲットからコールサイトに向かって情報が単純に逆方向に流れる可能性がある場合は、型が容易に推測でき、エラーはありません。そして、実際にJava 8のコンパイラはこれを行うことができます。別の答えが述べられているように、この豊富な型推論は、Java 8で追加されているラムダ、およびラムダを利用するために作られているJava APIの拡張に非常に役立ちます。

プレリリースビルドJava 8 with JSR 335 lambdasを上記のリンクからダウンロードできます。質問内のコードを警告やエラーなしにコンパイルします。

3

コンテキストからの型の推論は複雑すぎます。主な障害はおそらくメソッドのオーバーロードです。たとえば、f(g(x))は、f()を適用するかどうかを判断するために、g(x)の型を知る必要があります。それでもg(x)のタイプはf()のパラメータタイプから推測する必要があるかもしれません。いくつかの言語では、メソッドのオーバーロードが禁止されているため、型推論が簡単になります。

Java 8では、サンプルがコンパイルされます。 Javaチームは、ラムダ式のユースケースに起因して型推論を広げる傾向にあります。それは簡単な仕事ではありません。

のJava 7のためのJava言語仕様は、単にJavaの7のとおりメソッド呼出し式(セクション15.12)

関連する問題