2017-10-18 10 views
2

タイトルには、SearchTree.Entry<K, V>のような項目の上にIterableである必要があるカスタムデータ構造SearchTreeを設計しようとしています。 SearchTreeは単なるインターフェイスです。私が何をしたいかインターフェイスとそのサブクラスとその型とサブタイプの一般的なイテレータ

SearchTree<K, V>インタフェースで定義されているようKVのそれ自身のサブタイプでSearchTree<K, V>を実装するクラスはまた、イテレータを実装することが可能であることを持っていることです。

SearchTree.java

public interface SearchTree<K extends Comparable<? super K>, V> extends Iterable<SearchTree.Entry<K, V>> { 

    static interface Entry<K, V> { 

     K getKey(); 

     V getValue(); 

     void setValue(V value); 
    } 
} 

そして今、私は、インターフェイスを実装するクラスがあるとします。

BST.java

public class BST<K extends Comparable<? super K>, V> implements SearchTree<K, V> { 

    @Override 
    public Iterator<Entry<K, V>> iterator() { 
     // return some bst specific iterator 
    } 
} 

BSTNode.java

public class BSTNode<K extends Comparable<? super K>, V> implements SearchTree.Entry<K, V> { // ... 
} 

今、明らかに、BST IteratorBSTNode以上のオブジェクトを反復処理する必要があり、それが何かとしてそれを宣言するために理にかなってlike:

BSTIterator.java

public class BSTIterator<K extends Comparable<? super K>, V> implements Iterator<BSTNode<K, V>> { 
} 

しかし、すぐに戻ってBSTIteratorのインスタンスのようなものとして返されるべきBST.javaから問題へ:

public class BST<K extends Comparable<? super K>, V> implements SearchTree<K, V> { 

    @Override 
    public Iterator<Entry<K, V>> iterator() { 
     return new BSTIterator<>(); 
    } 
} 

そして今

BST.java BSTIteratorの型引数を推定できません<>です。 この問題を回避するための賢明な方法はありますか?そのため、インターフェイスにジェネリックイテレータを持たせて、SearchTreeを実装しているクラスの具体的なイテレータの実装をジェネリック型をサブクラス化できるようにしますか?

+0

'? 「比較可能」の「スーパー」となります。オブジェクトをそのスーパータイプのインスタンスと比較することは今までのところ意味がありません。 –

答えて

2

もうすぐです。反復子BSTIteratorは、Iterator<BSTNode<K, V>>の代わりにIterator<SearchTree.Entry<K, V>>を実装する必要があります。返されたイテレータの型が保証する必要があるからだと思います。Entry<K, V>、特にBSTNodeではありません。

public class BSTIterator<K extends Comparable<? super K>, V> 
    implements Iterator<SearchTree.Entry<K, V>> { 
    // ... 
} 

public class BST<K extends Comparable<? super K>, V> 
    implements SearchTree<K, V> { 

    @Override 
    public Iterator<SearchTree.Entry<K, V>> iterator() { 
     return new BSTIterator<>(); 
    } 
} 
0

これにはいくつかの方法があります。


最も直接的な方法は何ですかNeil describes in his answerです。しかし、タイプ情報を捨ててしまいます。たとえば、BSTIteratorを直接使用する場合は、要素をそのままBSTNodeにキャストする必要があります。


ハック(しかし、実際には、完全に安全な)アプローチはIterator<T>には、消費者法が存在しないことに注意することです:あなたは今までget()を経由して、そこから値を取得する(または他の要素があるのか​​どうかを確認、または削除することができます以前に得られた要素)。

このように、Iterator<SubclassOfT>Iterator<T>として使用することは完全に安全です。 Javaの型システムは、それが安全だということを知らないので、あなたはキャストする必要があります。

return (Iterator<SearchTree.Entry<K, V>>) (Iterator<?>) new BSTIterator<K, V>(); 

@SuppressWarnings("unchecked")を追加します。


これを行うにはグロスで-異なるウェイウェイはSearchTreeが上位囲まれたタイプを返すイテレータを実装することです:これは

public interface SearchTree<K extends Comparable<K>, V> 
    extends Iterable<? extends SearchTree.Entry<K, V>> 

ビット総額を今理由iterator()メソッドではIterator<? extends SearchTree.Entry<K, V>>が返されます。その場合は?が付いています。

有効なJava 2nd EdあなたのAPIのユーザーがワイルドカードを気にする必要がある場合、間違った設計をしていることになります。 (アイテム28、具体的には137ページ、手元にコピーがある場合)。


それを行うための別の方法は、明示的にIteratorで要素の型の型変数を追加することです:

public class BST<K extends Comparable<K>, V> 
    implements SearchTree<K, V, BSTNode<K, V>> 

public interface SearchTree<K extends Comparable<K>, V, T extends SearchTree.Entry<K, V>> 
    extends Iterable<T> 

今、あなたは、としてあなたBSTを宣言することができます

これは最も多くのタイプの情報を伝えますが、これは絶対に良いと主張しません。なぜなら、変数を宣言するたびに3つのタイプの変数を持つからです。SearchTreeは、特に第3のものが第1のものと第2のものを含むことが多いので、特に一般的なクラッタである。

SearchTree<String, Integer, ? extends SearchTree.Entry<String, Integer>> 

ここには、超素晴らしいクリーンオプションはありません。個人的に、私は最初の、ハッキーなオプションに行くだろう、なぜならa)それは本当に安全だからです! b)実装クラス内にハックが隠されている。

関連する問題