7

次のような Interator を書きたいと思います。

class Plant { }
class Tree extends Plant { }
class Maple extends Tree { }

// Iterator class: compiler error on the word "super".
class MyIterator<T super Maple> implements Iterator<T> {
    private int index = 0;
    private List<Maple> list = // Get the list from an external source.

    public T next() {
         Maple maple = list.get(index++);
         // Do some processing.
         return maple;
    }

    // The other methods of Iterator are easy to implement.
}

概念的には、それぞれに個別のクラスを記述せずに、Tree または Plant (常に Maples ですが) を返すように見えるイテレータを用意するという考え方です。

T super Mapleしかし、コンパイラは、 ;で生成すると気に入りません。どうやら、を使用してのみクラスを生成できますT extends Something。同じことを達成するための良い方法を知っている人はいますか?

質問する動機は、API にインターフェイスを使用するプログラムがあることです。インターフェイスの反復子を返すメソッド (API 用) と、実装クラスの反復子を返すメソッド (内部使用用) が必要です。

4

5 に答える 5

4

参照:型パラメーターの下限がないのはなぜですか?

于 2012-05-03T20:55:44.110 に答える
3

Mapleが aTreeと a の場合Plant、両方を拡張するため、使用したいスーパー句のポイントは何ですか? 古典的なサブタイプ ポリモーフィズムによって、Mappleto Object、 to 、TreeまたはPlantreference に割り当てることができます。

? extends Tとは両方とも? super Tワイルドカードであり、型パラメーターを置き換える型引数として宣言されますT

あなたがしようとしているのは、型パラメーターではなく型引数の境界を定義することです。型パラメーターを境界なしで T として宣言するだけでよく、それを使用するときは、型引数としてワイルドカードを使用します。

class MyIterator<T> implements Iterator<T> { ... }

そして、あなたがそれを使うとき:

MyIterator<? super Maple> iter;
于 2012-05-03T20:50:31.437 に答える
1

さて、あなたのイテレータは maple に対するイテレータを返しますが、それを Plant に対するイテレータとしてキャストしたいとします。

Iterator には、オブジェクトをリストの iterator があるポイントに入れるメソッド insertInto(T t) があると (少しの間) 考えてみましょう。. イテレータを Iterator<Plant> としてキャストする場合、 i.insertInto(myCarrot) を呼び出しても問題ないことを意味します-ニンジンは植物であるためです。しかし、これはタイプに違反します。ニンジンをカエデの基になるリストに入れようとすることになります。

つまり、イテレータはPlants のイテレータではなく、古いプラントをメソッド引数として取りません。そのため、そのようにキャストまたは生成することはできません。

于 2012-05-04T02:59:22.893 に答える
0

どうやらこれを行う理想的な方法はないようですので、最適とは言えない解決策を 2 つ提案します。

1 つ目は、次のようなラッパー イテレータです。

public class SuperTypeIterator<E> implements Iterator<E> {
    private final Iterator<? extends E> iter;

    public SuperTypeIterator(Iterator<? extends E> iter) {
        this.iter = iter;
    }

    @Override
    public E next() {
        return iter.next();
    }

    // And similarly for the other methods of Iterator
}

これにより、次のように戻り値の型を変更できます。

Iterator<Plant> getPlantIterator() {
    return new SuperTypeIterator<Plant>( new MapleIterator() );
}

これにより、新しいオブジェクトの作成を犠牲にして、完全なタイプ セーフが提供されます。

別の方法は、未チェックのキャストを使用することです。

Iterator<Plant> getPlantIterator() {
    return (Iterator<Plant>) (Iterator<?>) new MapleIterator();
    // Yes, the double cast is necessary to get it to compile.
}

これにより、ラッパー オブジェクトを作成する必要がなくなりますが、すべての型の安全性が犠牲になります。

于 2012-05-07T09:54:18.553 に答える
0

super-bounded 型パラメーターを宣言することは許可されておらず、理由はそれが有用ではないということです

読み取り専用イテレータを実装している場合、そのようにバインドすると便利な場合があるため、それは理にかなっています。

簡単なオプションは、そのままにして実装するIterator<Maple>Iterator<T>、型チェックを行うことです。

于 2012-05-03T20:57:34.833 に答える