28

Java では、共分散により、API 設計者は、インスタンスが特定の型またはその型のサブタイプのいずれかとして一般化される可能性があることを指定できます。例えば:

List<? extends Shape> shapes = new ArrayList<Circle>(); 
// where type Circle extends Shape

反変性は逆です。インスタンスが特定のタイプまたはスーパータイプとして一般化される可能性があることを指定できます。

List<? super Shape> shapes = new ArrayList<Geometry>();
// where Shape extends Geometry

Javaジェネリックの反変性はどのように役立ちますか? いつ使用することを選択しますか?

4

3 に答える 3

36

Java Generics and Collectionsからの関連する抜粋を次に示します。

2.4. ゲットアンドプットの原則

可能な限りワイルドカードを挿入することをお勧めしますが、使用するワイルドカードをどのように決定するのでしょうか? どこで を使用する必要がextendsあり、どこで を使用する必要がsuperあり、ワイルドカードを使用することがまったく不適切な場所はどこですか?

幸いなことに、単純な原則によってどちらが適切かが決まります。

Get and Put の原則: extends構造体から値を取得する場合のみワイルドカードを使用し、super 値を構造体に入れるだけの場合はワイルドカードを使用し、get と put の両方を行う場合はワイルドカードを使用しないでください。

この原則が copy メソッドの署名で機能していることは既に確認しました。

public static <T> void copy(List<? super T> dest, List<? extends T> src)

メソッドはソース src から値を取得するため、ワイルドカードを使用して宣言さextendsれ、値を宛先 dst に入れるため、superワイルドカードを使用して宣言されます。イテレータを使用するときは常に構造体から値を取得するため、extends ワイルドカードを使用してください。数値のコレクションを取得し、それぞれを double に変換して合計するメソッドを次に示します。

public static double sum(Collection<? extends Number> nums) {
    double s = 0.0;
    for (Number num : nums) s += num.doubleValue();
    return s;
}
于 2010-10-05T12:10:02.287 に答える
34

さて、あなたの2番目の例では、次のように書くことができます:

Shape shape = getShapeFromSomewhere();
shapes.add(shape);

一方、最初のフォームではそれができませんでした。共分散ほど頻繁には役に立ちませんが、私はあなたに認めます。

それが役立つ可能性のある領域の 1 つは、比較の観点からです。たとえば、次のことを考慮してください。

class AreaComparer implements Comparator<Shape>
...

これを使用して、任意の 2 つの形状を比較できます。たとえば、並べ替えに使用できればよいでしょう。List<Circle>幸いなことに、反変性でそれを行うことができます。そのためCollections.sort、 of のオーバーロードがあります。

public static <T> void sort(List<T> list, Comparator<? super T> c)
于 2010-10-05T05:58:24.700 に答える
8

たとえば、Collections.addAll()メソッドを実装する場合、T 型または T のスーパータイプを含むことができるコレクションが必要です。メソッドは次のようになります。

public static <T> void addAll(Collection<? super T> collection, T... objects) {
    // Do something
}
于 2010-10-05T06:02:41.640 に答える