25

私はEffective Javaのジェネリックに関する章を読んでいます。

との違いを理解するのを手伝ってSetください。Set<?>Set<Object>

次の段落は本からの抜粋です。

クイック レビューとして、Set<Object>任意の型のオブジェクトを含むことができるセットを表すパラメーター化された型Set<?>であり、不明な型のオブジェクトのみを含むことができるセットを表すワイルドカード型でSetあり、ジェネリック型をオプトアウトする生の型です。システム。

「いくつかの未知のタイプ」とはどういう意味ですか? すべての未知の型は型Objectですか? Set<?>その場合、との具体的な違いは何Set<Object>ですか?

4

8 に答える 8

20
  • 生の type( ) は、ジェネリック型情報がまったくないSetかのように型を扱います。型引数が無視されるだけでなく、その型のメソッドが持つ可能性のある他のすべての型引数も無視されるという微妙な効果に注意してください。任意の値を追加でき、常に が返されます。TObject
  • Set<Object>は、すべてのオブジェクト (つまり、すべてのSetオブジェクト)を受け入れ、 type のオブジェクトを返す です。ObjectObject
  • Set<?>特定の未知Setの型のすべてのオブジェクトを受け入れ、その型のオブジェクトを返す です。この型についてはもわかっていないため、そのセットには ( を除いて) 何も追加できません。返される値についてわかっていることは、それらが のサブタイプであるということだけです。nullObject
于 2011-09-09T11:00:43.403 に答える
3

実行時に、JVM はSet型の消去のために参照するだけです。

コンパイル時に、違いがあります。

Set<Object>で型Eをパラメータ化するとObjectSet.add(E element)にパラメータ化されSet.add(Object element)ます。

Set<?>一方、 は型にワイルドカードを追加するEため、Set.add(E element)に変換されSet.add(? element)ます。これはコンパイルできないため、Java は代わりにSet.add(null element). これは、そのセットに何も追加できないことを意味します (null を除く)。その理由は、ワイルドカードが不明なタイプを参照しているためです。

于 2011-09-09T11:03:19.257 に答える
3

「未知のタイプ」とは

まさにそれが意味すること - にSetいくつかの一般的なパラメーターがありますが、それが何であるかはわかりません。

したがって、Set<?>変数に割り当てられたセットSet<String>は、 、またはSet<Integer>、または 、Set<Map<Integer, Employee>>または他の特定の型を含むセットである可能性があります。

では、それをどのように使用できるかについて、それはどういう意味ですか?それが何であれ、それから得られるものはすべて のインスタンスになります?。型パラメーターが何であるかがわからないため、セットの要素が割り当て可能になることよりも具体的なことは言えませんObject(すべてのクラスがそれから拡張されているため)。

また、セットに何かを追加することを考えている場合、addメソッドは?(セット内のオブジェクトのタイプであるため、これは理にかなっています) を取ります。しかし、特定のオブジェクトを追加しようとすると、それがタイプ セーフであることをどのように確認できるのでしょうか? できません-文字列を挿入している場合Set<Integer>、たとえば、ジェネリックから取得したタイプセーフを破る可能性があります。したがって、ジェネリック パラメータの型がわからない場合、この型の引数を指定することはできません (null任意の型の「インスタンス」であるため、 の 1 つの例外を除きます)。


ほとんどのジェネリック関連の回答と同様に、コレクションは本能的に理解しやすいため、これはコレクションに焦点を当てています。ただし、引数はジェネリック パラメーターを受け取るすべてのクラスに適用されます。無制限のワイルドカード パラメーターで宣言されている場合、引数?を指定することはできず、受け取るその型の値は にのみ代入できます。Object

于 2011-09-09T16:38:32.900 に答える
2

Set: ここにはジェネリックはありません。安全ではありません。必要なものを追加します。

Set<?>: 私たちのスコープからはわからない特定のタイプのセット。と同じSet<? extends Object>。任意のタイプのセットを参照できますが、そのタイプは、セットが実際にインスタンス化されるポイントで定義する必要があります。ワイルドカード参照では、セットを変更できません (null 以外のものを追加または削除することはできません)。ビューのようなものです。

Set<Object>: オブジェクトを含むセット (サブクラスではなく、基本クラスのみ)。HashSet<Object>つまり、オブジェクト型のコレクションを使用してセットをインスタンス化できるということですHashSet<String>。もちろん、任意のタイプの要素をセットに追加できますが、たまたますべてが Object または Object のサブクラスであるという理由だけで。セットが Set として定義されている場合、Number と Number のサブクラスのみを追加でき、それ以上は追加できません。

于 2011-09-09T11:00:50.653 に答える
1
Set<?> set = new HashSet<String>();
set.add(new Object()); // compile time error

セットの要素タイプが何を表すかわからないため、オブジェクトを追加することはできません。このメソッドは、の要素タイプであるタイプのadd()引数を取ります。実際の型パラメーターがである場合、それはいくつかの未知の型を表します。追加するために渡すパラメータはすべて、この不明なタイプのサブタイプである必要があります。タイプがわからないため、何も渡すことができません。唯一の例外は 、すべてのタイプのメンバーであるです。ESet?null

が与えられると、結果Set<?>を呼び出しget()て利用できます。結果のタイプは不明なタイプですが、オブジェクトであることは常にわかっています。したがって、の結果をget()型の変数に割り当てるか、型が期待されるObject場所にパラメータとして渡すのが安全です。Object

于 2011-09-09T11:26:34.493 に答える
1

私はこの項目を友人に説明していて、unsafeAdd の例に対するカウンターとして「safeAdd」メソッドを具体的に求めました。だからここにあります。

public static void main(String[] args) {
    List<String> strings = new ArrayList<String>();

    unsafeAdd(strings, new Integer(42)); // No compile time exceptions

    // New 
    safeAdd(strings, new Integer(42)); // Throwing an exception at compile time


    String s = strings.get(0); // Compiler-generated cast

}

private static void unsafeAdd(List list, Object o) {
    list.add(o);
}


private static <E> void safeAdd(List<E> list, E o) {
    list.add(o);
}
于 2014-01-08T04:13:04.657 に答える
1

Set<Object>との違いはSet<?>、型の変数には、Set<?>次のように、より具体的なジェネリック型を割り当てることができることです。

Set<?> set = new HashSet<Integer>();

whileSet<Object>のみを割り当てることができますSet<Object>:

Set<Object> set = new HashSet<Integer>(); // won't compile

Set<Object>、任意のオブジェクトを入れることができるため、依然として便利です。その意味では raw によく似ていSetますが、ジェネリック型システムの方がうまく機能します。

于 2011-09-09T11:00:20.747 に答える