8

コレクションのコレクションを単一のセットに変換するための、この便利な汎用関数を作成しました。

public static <T> Set<T> makeSet(Collection<Collection<T>> a_collection) {
    Iterator<Collection<T>> it = a_collection.iterator();
    Set<T> result = new HashSet<T>();
    while (it.hasNext()) {
        result.addAll(it.next());
    }
    return result;
}

それから私はそれを呼び出そうとしました:

    List<List<String>> resultLists = ... ;
    Set<String> labelsSet = CollectionsHelper.makeSet(resultLists);

次のエラーを受け取りました。

<T>makeSet(java.util.Collection<java.util.Collection<T>>) in CollectionsHelper 
cannot be applied to (java.util.List<java.util.List<java.lang.String>>)

今、 aList Collectionであり、 aString Tです。では、なぜこれが機能しないのですか?どうすれば修正できますか?

4

6 に答える 6

8

署名は次のとおりです。

public static <T> Set<T> makeSet(Collection<? extends Collection<T>> coll);

基本的List<S>に はのサブタイプであるという理由だけで のサブタイプではありません。そのプロパティは共分散と呼ばれ、Java ではジェネリック型は共変ではありません( scalaなどの他の言語には共変のジェネリック型が含まれます)。List<T>ST

Collection<T>に何かを追加できるはずなので、あなたがしたことはうまくいきませんでしたCollection<Collection<T>>。たとえば、署名を使用すると、これは有効な実装になります。

public static <T> Set<T> makeSet(Collection<Collection<T>> coll) {
    coll.add(new HashSet<T>());
    return null;
}

ただし、このメソッドを次のように呼び出します。

List<List<String>> outside = new LinkedList<List<String>>();
makeSet(outside); //actually this line will not compile!
List<String> oops = outside.get(0); //oh dear - it's a HashSet

それで、これは同じ問題につながりますか?いいえ!その理由は、未知の型でパラメーター化されたコレクションにコンパイラーが何も追加できないためです。

public static <T> Set<T> makeSet(Collection<? extends Collection<T>> coll) {
    coll.add(new HashSet<T>()); //this line will not compile
    return null;
}

ワイルドカードを持つことは、やりたいことを実行できるようにするために最初に必要でした。おそらく、それが許可されるようにCollection.addAllメソッドがどのように生成されたかによって最もよく示されます。List<Number>.addAll(List<Integer>)

boolean addAll(Collection<? extends T> coll)
于 2009-11-20T17:53:14.500 に答える
7
public static <T> Set<T> makeSet(Collection<? extends Collection<T>> a_collection) {
    Iterator<? extends Collection<T>> it = a_collection.iterator();
    Set<T> result = new HashSet<T>();
    while (it.hasNext()) {
            result.addAll(it.next());
    }
    return result;
}
于 2009-11-20T17:55:48.713 に答える
4

いいえ、そうではありません。

宣言を次のように変更します

public static <T> Set<T> makeSet(Collection<? extends Collection<T>> a_collection) {
    ....
}

2 つのジェネリック型がサブタイプになるのは、型引数が同一である (またはワイルドカードが含まれているためCollection<String>、 のサブタイプではない) 場合のみです。ジェネリック チュートリアル のサブタイプのセクションをCollection<Object>確認してください。

于 2009-11-20T17:53:08.170 に答える
3

これは、より一般化された質問「Collection<Circle>の種類はCollection<Shape>?」の特殊なバージョンです。

答えは (おそらく驚くべきことですが)いいえです。

その理由は、C++ FAQの C++ コンテキストで詳しく説明されています。これは一般的な OO の質問なので、同じ一般的な理由が適用されます。

たとえば、 aCollection<Circle> 一種のである代替宇宙を考えてみましょうCollection<Shape>。このユニバースでは、次のようなことができます。

Collection<Circle> circles = new Collection<Circle>();
Collection<Shape> shapes = circles; // OK, we're in an alternate universe
shapes.Add(new Circle()); // OK, we're adding a circle to a collection of circles
shapes.Add(new Square()); // Asplode!  We just added a square to a collection of circles.

Square (Shape) が、実際には円のコレクションである形状のコレクションに追加されるとどうなるでしょうか? 良い答え はありません。

同じ理由が aCollection<List<T>>と aにも当てはまりますCollection<Collection<T>>。Aは a の代わりに使用できないためCollection<List<T>>、一種ではありません。はコレクションのコレクションに追加できますが、 のコレクションには追加できません。Collection<Collection<T>>Collection<Collection<T>>Queue<T>List<T>

于 2009-11-20T17:55:26.200 に答える
3

あまりにも醜いので、正解を投稿するのはほとんど嫌ですが、トップ 3 の回答がこれを見逃しているので、私はやむを得ないと感じています。

public static <T> Set<T> makeSet(
    Collection<? extends Collection<? extends T>> coll)

あなたはその権利を読みます。2 つの「? extends」。それ以外の場合、List<Integer> と List<Double> を組み合わせて Set<Number> を取得することはできません。これは論理的に可能であるはずです。

ジェネリック内にネストされたジェネリックに到達すると、事態は常に厄介になります。

代わりに、より単純な答えを選択することは完全に許されます。:) 論理的に必要な場所で常に機能するとは限らないことを知っておいてください。

ちなみに、Google Collectionsを使用Iterables.concat(...)すると、これを行うために、またはImmutableSet.copyOf(Iterables.concat(...))重複除外が必要な場合に使用できます。

于 2009-11-20T23:55:11.030 に答える
0

これは、Java 1.0 が開発されて、起こっていたすべてのばかげた C++ テンプレートを単純化するようになったようなものです。オブジェクトのコレクションから特定のインスタンスのセットへの愚かなキャストを避けるために、5 つの複雑なレイヤーを追加します。いたるところにキャストしてコードを醜くしていることがわかった場合は問題ありませんが、実際には、これはコードの 50 万行に 1 回程度発生するに違いありません。ええ、ええ、この種の技術的な詳細を見つけることができるのは良いことですが、この道をたどり始めると、コードは本当に保守しやすくなりますか?

于 2009-11-20T18:21:56.173 に答える