24

私は主にC#開発者であり、友人にデータ構造を教えていました。彼らは大学でJavaを使用しており、Javaでそのような表現を見ました。

void printCollection(Collection<?> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

私はC#でそのようなことを見たことがないので、JavaCollection<T>との違いは何だろうか?Collection<?>

void printCollection(Collection<T> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

上記のように書いていたのではないかと思います。ドキュメントの男は比較Collection<Object>してCollection<T>いましたが。

例はhttp://docs.oracle.com/javase/tutorial/extra/generics/wildcards.htmlから取得されます

4

5 に答える 5

29

Collection<?>不明なタイプのパラメータのコレクションです。

発信者に関する限り、違いはありません

void printCollection(Collection<?> c) { ... }

<T> void printCollection(Collection<T> c) { ... }

ただし、後者を使用すると、実装でコレクションの型パラメーターを参照できるため、多くの場合、この方法が推奨されます。

前者の構文が存在するのは、適切なスコープで型パラメーターを導入できるとは限らないためです。たとえば、次のことを考慮してください。

List<Set<?>> sets = new ArrayList<>();
sets.add(new HashSet<String>());
sets.add(new HashSet<Integer>());

?あるタイプのパラメーターで置き換えるとT、のすべてのセットがsets同じコンポーネントタイプに制限されます。つまり、次の試行で証明されるように、異なる要素タイプのセットを同じリストに入れることができなくなります。

class C<T extends String> {
    List<Set<T>> sets = new ArrayList<>();

    public C() {
        sets.add(new HashSet<String>()); // does not compile
        sets.add(new HashSet<Integer>()); // does not compile
    }
}
于 2012-05-27T23:07:15.303 に答える
19

宣言Collection<?>(「不明のコレクション」と発音)は、要素タイプがすべてに一致Collection<T>するコレクションですが、タイプのコレクションを表しTます。

いつものように、ジェネリックに関するアンジェリカ・ランガーのFAQには、このトピックに関する広範な議論があります。Javaのジェネリック、特に無制限のワイルドカード(この質問の主題)について完全に理解するには必読です。FAQからの引用:

無制限のワイルドカードは「?」のように見え、すべてのタイプのファミリを表します。無制限のワイルドカードは、ジェネリック型のインスタンス化の引数として使用されます。無制限のワイルドカードは、パラメーター化された型の型引数に関する知識が必要ない状況で役立ちます

技術的な詳細については、Java言語仕様の§4.5.1型引数とワイルドカードのセクションを確認してください。

型引数は、参照型またはワイルドカードのいずれかです。ワイルドカードは、型パラメーターに関する部分的な知識のみが必要な状況で役立ちます。

于 2012-05-27T22:25:58.770 に答える
5

Collection<T>あなたと一緒にできる

void printCollection(Collection<T> c) {
    for (T e : c) {
        System.out.println(e);
    }
}

コレクションにオブジェクトが含まれてCollection<?>いることだけを知っています。

于 2012-05-27T22:28:57.500 に答える
5

無制限のワイルドカード(?)を使用するものは、実際には? extends Object(Objectを拡張するもの)を意味します。

これは、Javaでは、読み取り専用の性質を意味します。つまり、汎用構造からアイテムを読み取ることは許可されていますが、要素の実際のタイプを特定できないため、元に戻すことはできません。それ。

printCollectionしたがって、少なくとも、タイプを想定する必要がある状況に遭遇するまでは、これは議論中の方法では非常に有効なアプローチであると思います。

2つのうちどちらかを選択する必要がある場合、2番目の方法(タイプパラメーターTを使用)は、少なくともコレクションに特定のタイプがあると想定できるため、よりクリーンなアプローチでTあり、特定のシナリオで役立つことが証明できます。

たとえば、コレクションを同期する必要がある場合は、次のようにすることができます。

<T> void printCollection(Collection<T> c) {
    List<T> copy = new ArrayList<T>();
    synchronized(c) {
        copy.addAll(c);
    }
    for (T e : copy) {
        System.out.println(e);
    }
}

タイプの新しいコレクションを非常に簡単に作成しT、元のコレクションのすべての要素をこの2番目のコレクションにコピーします。Tコレクションのタイプはであり、ではないと想定できるため、これを行うことができます?

もちろん、最初の方法(uboundedワイルドカードを使用)でも同じことができますが、それほどクリーンではないため、コレクションのタイプはオブジェクトであり、オブジェクトではないと仮定する必要がありました?(これは、として有効に使用することはできません)。引数を入力します:) new ArrayList<?>()

void printCollection(Collection<?> c) {
    List<Object> copy = new ArrayList<Object>();
    synchronized(c) {
        copy.addAll(c);
    }
    for (Object e : copy) {
        System.out.println(e);
    }
}
于 2012-05-27T23:52:33.093 に答える
0

タイプTの新しいコレクションを非常に簡単に作成し、元のコレクションのすべての要素をこの2番目のコレクションにコピーしました。コレクションのタイプはTであり、?ではないと想定できるため、これを行うことができます。

もちろん、最初の方法(無制限のワイルドカードを使用)でも同じことができますが、それほどクリーンではないため、コレクションのタイプはオブジェクトであり、オブジェクトではないと仮定する必要がありましたか?(これは、型引数として有効に使用することはできません:new ArrayList <?>())。

于 2022-01-11T03:02:39.273 に答える