3

自己参照ジェネリック パラメータと同じスーパー クラスのパラメータを持つクラスがあります。static 関数には、クラスと同じ境界があります。

public class Bar<T extends Bar<T, C>, C extends Bar<C, ?>> {

    Bar() {
        foo((T) null);
        foo((C) null);//compile error
    }

    static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ?>> void foo(S_T t) {
    }
}

これにより、次のエラーが発生します。

範囲の不一致: Bar<T,C> 型のジェネリック メソッド foo(S_T) は、引数 (C) には適用できません。推定された型 C は、境界付きパラメーター <S_T extends Bar<S_T,S_C>> の有効な代替ではありません

isとワイルドカードが a であるため、渡せCない理由がわかりません。これは、宣言の 2 番目のパラメーターが Bar を拡張すると述べているためです。foo()CBar<C,?>Bar

これはおそらく悪い考えであり、理解しにくいコードを生成することはわかっていますが、なぜこれがコンパイルされないのかを本当に知りたいです。

4

2 に答える 2

2

簡単に言えば、Java の型推論は実際にはかなり不十分だということです。

Java は?、 の宣言でワイルドカードに対してインテリジェントな推論を実行して、ワイルドカードBarが論理的に境界付けられていることを推論しBar< ?, ? >ません (また、その境界内の?s 自体が境界付けられていることなども推論しません)。単独で置く?と、それがJavaが知っているすべてです。の宣言でその境界をワイルドカードに入れることを妨げるものは何もありませんがBar、それでも Java には役立ちません。Java は、2 つの別個の が同じ型を参照していると想定することはありません?。より詳細な分析により、同じ型を参照する必要があることが示唆されたとしてもです。つまり、次のコードでもコンパイル エラーが持続します。

public class Bar<T extends Bar<T, C>, C extends Bar<C, ? extends Bar<?, ? extends Bar<?, ?>>>> {

    Bar() {
        foo((T) null);
        foo((C) null);//compile error
    }

    static <S_T extends Bar<S_T, S_C>, S_C extends Bar<S_C, ? extends Bar<?, ? extends Bar<?, ?>>>> void foo(S_T t) {
    }
}
于 2012-06-12T00:06:34.597 に答える
0

私はジェネリックスの亀裂ではありませんが、問題はfoo()の型を次のように宣言することだと思います

<S_T extends Bar<S_T,S_C> > void foo(S_T)

次に、の異なる静的タイプを必要とする2つの異なるコンテキストでそれを呼び出しますfoo()

最初のコンテキストでS_TはタイプTがあり、2番目のコンテキストではタイプがありCます。ただしT、およびは、静的に互換性のないタイプであるおよびCとして宣言されます。コンパイラーは最初の呼び出しでタイプを把握し、それからタイプが全体を通して同じでなければならないと正しく仮定していると思いますが、そうではありません。Bar<T,?>Bar<C,?>foo()

于 2012-06-11T18:39:22.337 に答える