0

次の一般的な定義がコンパイラの警告を生成しないのはなぜでしょうか。

class MyClass<T extends List> { }

上記の定義がどのように異なるか

class MyClass<T extends List<?>> { }

ジェネリックについて読むときはいつでも、生の型をどのように避けるべきかについて読んでいます。その結果、ジェネリック型を扱うときはいつでも、コンパイラの警告が表示されます。ただし、最初の定義内の生の型は、そのような警告を作成しません。

次に、未加工の型とジェネリック型の間の正確なサブタイプ定義はどのようになっているのだろうかと思います。この要約によると、生の型は一種の型チェックの「オプトアウト」であるため、生の型が関係するときは常に型チェックが単に非アクティブになります。この仮定は正しいですか?そして、これは上記の「生の」一般的な定義にどのように影響しますか?

ご協力ありがとうございました!

更新:あなたの言っていることは理解しています。しかし、これは私が混乱しているものではありません。このシナリオを見てください:

class MyClass<T extends MyClass<T>> {}

public void callWildcard1(MyClass<?> node) {
    callBound1(node);
}

public <T extends MyClass<T>> void callBound1(T node) {
    // Do something
}

public void callWildcard2(MyClass<?> node) {
    callBound2(node);
}

public <T extends MyClass> void callBound2(T node) {
    // Do something
}

一般的な制約のため、 to からの最初の呼び出しは許可されませcallWildcard1ん。callBound1ただし、2 番目は許可されます。「内部の生の型」なしで最初の呼び出しを実行するにはどうすればよいですか? コンパイラが最初のものを禁止する理由がわかりません。パラメータ有効なワイルドカード パラメータが意味するものはあり? extends MyClass<?>ませんか?

更新 2 :試行錯誤の結果、次のように定義することで問題を解決できることがわかりました。

public <T extends MyClass<? extends T> void callBound2(T node) {
    // Do something
}

理由はよくわかりませんが。しかし、この例を見ると、さらに混乱があります: (これは、私が実際にやろうとしていることの非常に単純なバージョンです。)

public void call() {
    genericCall1(new MyFilter<MyClass<?>>(), MyClass.class);
    genericCall2(new MyFilter<MyClass<?>>(), MyClass.class);
}

public <T extends MyClass<? extends T>> void genericCall1(MyFilter<T> filter, Class<? extends T> filterBoundary) {
  // Do something.
}

public <T extends MyClass<? extends T>, U extends T> void genericCall2(MyFilter<T> filter, Class<? extends U> filterBoundary) {
  // Do something.
}

class MyClass<T extends MyClass<T>> { }

class MyFilter<T extends MyClass<? extends T>> { }

なぜgenericCall1禁止されてgenericCall2いないのですか?繰り返しますが、私は真の理解ではなく、学術的な推測によって解決策を見つけました。ときどき、Java とそのジェネリックを扱っていると、泣きたくなることがあります...

4

1 に答える 1