7

ジェネリックが手に入らないこともあります。コードでは、最も一般的なバージョンのコレクションをよく使用します。たとえば、何かのセットが必要な場合は、次のように記述します。

Set<?> set1 = new HashSet<Object>();

それはコンパイラによって許可されており、なぜそうすべきではないのか-Set<?>と同じくらい一般Set<Object>的です(またはさらに一般的です..)。ただし、「ジェネリックのジェネリック」を使用すると、「よりジェネリック」になり、機能しません。

Set<Class<?>> singletonSet = new HashSet<Class<Object>>(); // type mismatch

何が起こっている?Set<Object>が に割り当て可能でSet<?>あり、Set<Class<Object>>に割り当てられないのはなぜSet<Class<?>>ですか?


私はいつもこの種の問題を回避する方法を見つけますが、この場合、これが許可されておらず、回避策ではない理由を本当に知りたいです。

4

5 に答える 5

6

これを考えると:

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>>();

したがって、そのコードがコンパイルされる理由を見つけるために、それを裏返しに読んで、明示的に実行してください。

  1. 最も内側: とObject互換性があり? Extends Objectますか? もちろんそうだ。

  2. 一番外側: と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>>();
于 2012-05-30T20:09:59.343 に答える
5

ジェネリックは Java では共変ではありません。この質問はあなたを助けるかもしれません:

Javaジェネリック共分散

于 2012-05-25T10:06:48.883 に答える
0

jdk1.6.0_22の下でEclipseで次のことを試しました:

Set<Class<?>> singletonSet = new HashSet<Class<Object>>();

コンパイラは私に次のことを教えてくれました:

Type mismatch: cannot convert from HashSet<Class<Object>> to Set<Class<?>>

私はこれに変更しましたが、うまくいきました:

HashSet<Class<Object>> singletonSet = new HashSet<Class<Object>>();

ジェネリックのジェネリックには、同じクラスのコレクションと同じクラスの収集されたオブジェクトが必要です。

これは Java のルールのようです。実行時にエラーが発生しやすく、重大なクラッシュが発生する可能性があるためです。したがって、このように書くとうまくいきます:

HashSet<Class<?>> singletonSet = new HashSet<Class<?>>();
于 2012-05-25T10:08:00.100 に答える
0
Set<Class<?>> 

これは次のように言います:任意のタイプのクラスのセット

HashSet<Class<Object>>

これは、Object 型でなければならないクラスの HashSet - したがって、Object.class オブジェクトのみが許可されます - Object にはクラス オブジェクトが 1 つしかないため、これはあまり意味がありません。

質問はまだ有効だと思いますが、クラスを使用するのではなく、別のサンプルを選択できるかもしれません。

于 2012-05-25T10:23:04.227 に答える
-1

ここでの答えは、あらゆる種類のオブジェクト型を受け入れるということです。

したがって、以下に記述する必要があります

Set<Class<?>> val = new HashSet<Class<?>>();

Objectここでは、あらゆる種類のものをSet

于 2012-05-25T10:08:38.187 に答える