5

あいまいなタイトルで申し訳ありません。Eclipse Juno (4.2) でコンパイルされますが、javac (1.7.0_09) ではコンパイルされない次のコードがあります。

package test;

public final class Test {
    public static class N<T extends N<T>> {}

    public static class R<T extends N<T>> {
        public T o;
    }

    public <T extends N<T>> void p(final T n) {}

    public void v(final R<?> r) {
        p(r.o);       // <-- javac fails on this line
    }
}

エラーは次のとおりです。

Test.java:13: エラー: クラス Test のメソッド p は、指定された型に適用できません。
        プロ);
        ^
  必須: T
  見つかった: N<CAP#1>
  理由: 推論された型が宣言された境界に準拠していません
    推測: N<CAP#1>
    境界: N<N<CAP#1>>
  ここで、T は型変数です。
    T は、メソッド <T>p(T) で宣言された N<T> を拡張します。
  ここで、CAP#1 は新しい型変数です:
    CAP#1 は、? のキャプチャから N<CAP#1> を拡張します。
1 エラー

質問は次のとおりです。

  1. これはバグですか、javacそれとも Eclipse のバグですか?

  2. javacメソッドの署名を変更せずにv(つまり、ワイルドカードを保持して) 、これを でコンパイルする方法はありますか?

    に変更<T extends N<T>> void v(final R<T> r)するとコンパイルされることは知っていますが、最初にこれを回避する方法があるかどうかを知りたいです。また、コンテンツには正確な制約が必要なタイプがあるため、メソッドpを に変更することはできません。<T extends N<?>> void p(final T n)T extends N<T>

4

1 に答える 1

6

T extends X<T>ワイルドカードは、型パラメーターが許可するような再帰式を壊すという点で制限されています。私たちは、あなたがやろうとしていることは、以下に基づいて安全であることを知っています:

  1. r.oT( で宣言R) であり、これはまたは extendsN<T>です。
  2. このメソッドは、または extends である( によって宣言された)p型の引数を取ります。TpN<T>
  3. したがって、rが として入力されたとしてもR<?>、呼び出しp(r.o)は理論的には合法であるはずです。

これはおそらく eclipse コンパイラーの推論です ( javac では許可されないジェネリックの特定のニュアンスを正しく許可することが知られています)。

javac でコンパイルする必要があり、前述のような署名を変更できないと仮定するとv、ジェネリック型チェックを「オプトアウト」する生の型を使用することが最善の方法です。

public void v(final R<?> r) {
    //necessary to placate javac - this is okay because [insert above reasoning]
    @SuppressWarnings("rawtypes")
    N nRaw = r.o;
    p(nRaw);
}
于 2012-11-03T23:42:45.923 に答える