11

次のサンプルでは、​​コンパイラがFoo.create()inの最初の呼び出しでジェネリック引数を推論できるのにFoo.test()、2 番目の呼び出しでは推論できないのはなぜですか? 私はJava 6を使用しています。

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
        }
    }
}

(コンパイルエラーはThe method func(Nonsense.Foo) in the type Nonsense.Bar is not applied for the arguments (Nonsense.Foo)です)。

注: コンパイラ エラーは test() の 3 行目で修正できることを理解しています - コンパイラが型を推測できないようにする特定の制限があるかどうかに興味があります。ここには十分な文脈があるように思えます

4

2 に答える 2

15

Java 7 の時点では、呼び出しているメソッドからのターゲット型情報を考慮してT、 の宣言で型変数を推測する前に、メソッドのオーバーロードの解決を続行する必要がありfuncます。この場合、 という名前のメソッドが 1 つしかないことがわかるので、それはばかげているように思えますが、これfuncは JLS によって義務付けられており、javacJava 7 以降の動作です。

コンパイルは次のように進行します。最初に、コンパイラは、func という名前のクラス Bar の静的メソッドへの呼び出しをコンパイルしていることを確認します。オーバーロードの解決を実行するには、メソッドが呼び出されているパラメーターを見つける必要があります。これは些細なケースですが、そうする必要があり、そうするまでは、メソッドの正式なパラメーターに関する情報がありません。実パラメータは 1 つの引数で構成され、その呼び出しFoo.create()は return として宣言されFoo<T>ます。Foo<T>繰り返しになりますが、ターゲット メソッドからの基準がないため、戻り値の型が is の消去であると推測することしかできFoo<Object>ません。

funcのオーバーロードのどれも の実パラメータと互換性がないため、メソッドのオーバーロードの解決は失敗し、Foo<Object>その結果としてエラーが発生します。

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

上記のリンクから、JSR 335 ラムダを使用した Java 8のプレリリース ビルドをダウンロードできます。問題のコードを警告やエラーなしでコンパイルします。

于 2013-02-01T17:57:41.607 に答える
3

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

Java 8 では、例がコンパイルされます。Java チームは、ラムダ式のユース ケースにより、型推論を拡張することに意欲的です。それは簡単な作業ではありません。

Java 7 の Java 言語仕様には、メソッド呼び出し式を仕様するためだけに 40 ページが含まれています (セクション 15.12)。

于 2013-02-01T17:22:36.050 に答える