これを考えると:
Set<?> set1 = new HashSet<Great>();
無制限のワイルドカードが何を意味するかを視覚化すると、これは機能します。無制限のワイルドカードのスロット型は と比較さextends
れるため、明示的に行うと。
Set<? extends Object> set1 = new HashSet<Great>();
読むと、グレート拡張オブジェクトですか?はい、それでコンパイルされます。
次に、これを考える:
Set<Class<Great>> set3 = new HashSet<Class<Great>>();
なぜ動くのかというと、SetとHashSetのパラメータを抽出するとClass<Great>
、この2つClass<Great>
はまったく同じ型です。
ワイルドカードがない場合、タイプは逐語的に直接比較されます。
そして、共変型を受け入れるように set3 を作成する場合 (これはコンパイルされます):
Set<? extends Class<Great>> set3a = new HashSet<Class<Great>>();
読むには、HashSet のClass<Great>
型は互換性がありますか、それとも Set に対して共変Class<Great>
ですか? はい、そうです。したがって、コンパイルされます。
もちろん、まったく同じ型であれば、そのような変数宣言を書く人はいないでしょうが、それは冗長です。代入の右側にあるジェネリックの具象クラスまたはインターフェイス パラメーターが左側のジェネリックの具象/インターフェイス (理想的には次のようなインターフェイス) と互換性があるかどうかを判断するために、ワイルドカードがコンパイラによって使用されています。
List<? extends Set<Great>> b = new ArrayList<HashSet<Great>>();
それを読むには、HashSet<Great>
共変Set<Great>
ですか?はい、そうです。したがって、コンパイルします
それでは、コード シナリオに戻りましょう。
Set<Class<?>> set3 = new HashSet<Class<Object>>();
この場合、同じルールが適用されます。最も内側から読み始めます。オブジェクトはワイルドカードと互換性がありますか? はい。その後、たまたまワイルドカードを持たない次の最も外側のタイプに進みます。したがって、ワイルドカードがない場合、コンパイラは と の間で逐語的なチェックを行いますがClass<Object>
、Class<?>
これらは等しくないため、コンパイル エラーが発生します。
最も外側にワイルドカードがある場合、それはコンパイルされます。したがって、おそらくあなたが意味したのはこれです。これはコンパイルされます:
Set<? extends Class<?>> singletonSet = new HashSet<Class<Object>>();
ただし、よりわかりやすい例を作成しましょう。インターフェイス (クラスは具象型) を使用してみましょう。たとえば、Set とします。これはコンパイルされます:
List<? extends Set<?>> b = new ArrayList<HashSet<Object>>();
したがって、そのコードがコンパイルされる理由を見つけるために、それを裏返しに読んで、明示的に実行してください。
最も内側: とObject
互換性があり? Extends Object
ますか? もちろんそうだ。
一番外側: とHashSet<Object>
互換性があり? extends Set<? extends Object>
ますか? もちろんそうだ。
1番目は、これです(コンパイル):
Set<? extends Object> hmm = new HashSet<Object>();
2番では、これです(コンパイル):
List<? extends Set<? extends Object>> b = new ArrayList<HashSet<Object>>();
ここで、最も外側のワイルドカードを削除してみましょう。型の互換性/共変チェックはコンパイラによって行われず、逐語的に比較されます。
これで、次の答えがわかりました。これらはコンパイルできますか?
List<Set<?>> b = new ArrayList<HashSet<Object>>();
// this is same as above:
List<Set<? extends Object>> b = new ArrayList<HashSet<Object>>();
あなたはすでにそれを推測しています、正しい...それはコンパイルされません:-)
上記を修正するには、次のいずれかを実行します。
List<? extends Set<? extends Object>> b = new ArrayList<HashSet<Object>>();
List<? extends Set<?>> b = new ArrayList<HashSet<Object>>();
次に、コードを修正するには、次のいずれかを実行します。
Set<? extends Class<? extends Object>> singletonSet =
new HashSet<Class<Object>>();
Set<? extends Class<?>> singletonSet = new HashSet<Class<Object>>();