繁体   English   中英

接口及其子类及其类型和子类型的通用迭代器

[英]Generic iterator for an interface and its subclasses and its types and subtypes

正如标题所说,我试图设计一个自定义的数据结构SearchTree这将需要Iterable通过条目,如SearchTree.Entry<K, V> SearchTree本身只是一个接口。

我想要做的是让任何实现SearchTree<K, V>和它自己的KV子类型的类也能够实现SearchTree<K, V>接口中定义的迭代器。

搜索树

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 Iterator应该遍历BSTNode对象,因此将其声明为如下内容是有意义的:

BST迭代器

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

但现在回从问题BST.java其中的实例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<>();
    }
}

现在这不起作用:无法推断 BSTIterator<> 的类型参数 有没有什么合理的方法可以解决这个问题,这样我就可以在我的接口中有一个通用迭代器,并从实现SearchTree的类中返回具体的迭代器实现,这样泛型类型也可以被子类化?

你很接近。 您的迭代器BSTIterator必须实现Iterator<SearchTree.Entry<K, V>>而不是Iterator<BSTNode<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<>();
    }
}

有几种方法可以解决这个问题。


最直接的方式是尼尔在他的回答中所描述的 但这会丢弃类型信息:例如,如果您想直接使用BSTIterator ,如果您想这样使用它们,则需要将元素转换回BSTNode s。


hacky(但实际上完全安全)的方法是注意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>> Iterator<? extends SearchTree.Entry<K, V>> :你被困住了? .

Josh Bloch 在Effective Java 2nd Ed 中声称,如果您的 API 用户不得不关心通配符,那么您的设计就错了。 (第 28 项,特别是第 137 页,如果您手头有副本)。


另一种方法是为Iterator中的元素类型显式添加类型变量:

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

现在您可以将您的BST声明为:

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

这传达了最多的类型信息,但我不会声称这绝对更好,因为每当你声明一个包含SearchTree变量时有 3 个类型变量只是一般的混乱,特别是因为第三个通常会再次包含第一个和第二个,例如

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

这里没有超级干净的选择。 就个人而言,我会选择第一个,hacky 选项,因为 a) 它真的很安全! b) hack 隐藏在实现类中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM