java迭代器/可迭代子接口

Posted

技术标签:

【中文标题】java迭代器/可迭代子接口【英文标题】:java iterator/iterable subinterface 【发布时间】:2010-11-25 08:53:50 【问题描述】:

我有各种类的接口,所有这些都应该实现Iterator,所以我有类似

public interface A extends Iterable<A>  ...otherMethods()... 

然而,对于具体的类,这意味着我必须使用

public class B implements A  public Iterator<A> iterator() ... 

当我更喜欢(或至少,我认为我更喜欢)使用 public Iterator&lt;B&gt; iterator() ... 以便类的具体使用可以具有显式类型(以防我想要不在接口中的方法时)是可用的,或者类似的。也许永远不应该出现?或者如果它出现了,那是糟糕的设计?

另一方面是使用迭代器接口

public interface A extends Iterator<A>  ...otherMethods()... 

具体的类用

编译就好了
public class B implements A  public B next() ... 

什么给了?

【问题讨论】:

有几个答案建议参数化 A,然后让 B 实现 A - 这很有效,我应该提到我之前已经开始工作了。问题是导致使用 AbstractClass 抽象的想法已经被打败了,或者我留下了原始类型,我吃了一堆警告,尽管我认为相对于我正在解决的问题是好吧,如果不漂亮的话。 所以,更具体地说,我正在寻找一个不需要子接口参数化的答案(如果存在)。 【参考方案1】:

卡尔是对的,我的第一个答案没有编译,但这似乎是。不确定这是否正是您想要的。

public interface A<T extends A> extends Iterable<T> 



public class B implements A<B> 

    @Override
    public Iterator<B> iterator() 
        return null;
    

【讨论】:

我不认为超类型可以使用通配符;至少,这是我的编译器告诉我的。 我以前试过这个,但是在抽象实现过程中需要 AbstractInterface x 的缺点似乎违背了抽象的目的,或者你正在吃关于原始类型的警告,这似乎一开始就违背了泛型的目的(更强的类型控制)。【参考方案2】:

我想这就是你想要的:

public interface A<T extends A<?>>  extends Iterable<T>

public class B implements A<B> 
  public Iterator<B> iterator() ...

【讨论】:

关于您想要一个不需要子类参数化的解决方案的评论:我认为这是不可能的(但是我不是泛型专家)。如果您使用 Iterator 接口,它会起作用,因为在这种情况下,您可以利用协变,而泛型接口不是协变的。请参阅 Angelika Langer 的出色泛型常见问题解答:angelikalanger.com/Articles/Papers/JavaGenerics/…【参考方案3】:

具体类可以很好地编译,因为 B 扩展了 A,并且从 Java 5 开始,子类的返回类型可以是超类返回类型的子类。

至于泛型,我遇到了同样的问题,我知道你有两个选择。

一个是参数化A:

 public interface A<T extends A> extends Iterable<T>

然后:

public class B implements A<B>

但是,这有一个缺点,即您需要提供 A 的参数,而不是固定它,即使您想要 A:

private class NoOneSees implements A<A>

关于是否真的想要Iterator&lt;B&gt;的问题,在Iterable的情况下,很可能是更可取的,并且考虑到这些是接口,重新声明参数的需要可能是合理的。如果你开始继承具体的类,它会变得有点复杂,对于除了 Iterable 之外有意义的东西,你可能需要协方差。例如:

public interface Blah<T> 
    void blah(T param);


public class Super implements Blah<Super> 
    public void blah(Super param) 


public class Sub extends Super 
    public void blah(Super param) 
   //Here you have to go with Super because Super is not paramaterized
   //to allow a Sub here and still be overriding the method.

同样对于协方差,您不能声明Iterator&lt;A&gt; 类型的变量,然后在其中分配Iterator&lt;B&gt;,即使B 扩展了A。

另一个选项是基于这样一个事实,即进一步的实现/子类仍将引用 A。

【讨论】:

可以通过将接口声明从 void blah(T param) 更改为 void blah(U param); 来稍微修复 super/sub rabbithole;【参考方案4】:

你的设计决定是你自己的,但我想不出任何理由让设计中的每个类都实现 Iterable。必须有某种东西包含在集合中,但实际上并不是集合本身。我会仔细研究基本设计。也许某些可迭代对象会希望返回与其自身无关的事物的迭代器。

【讨论】:

【参考方案5】:

其他答案具有正确的要点 - 但您将通过将泛型类型声明为来获得正确的机制

A<T extends A<T>>

这会强制类返回其自身类型或更低类型的迭代器 - 这样您就可以声明

class B implements A<B>

但不是

class B implements A<A>

我怀疑它更接近你想要的(即实现必须返回迭代器而不是简单地超过 As)。

请注意,您对IteratorIterable 的体验源于缺乏泛型类型的协方差; B 的实例A,但Iterator&lt;B&gt;不是Iterator&lt;A&gt;

【讨论】:

以上是关于java迭代器/可迭代子接口的主要内容,如果未能解决你的问题,请参考以下文章

java 中 iterator 为啥翻译成迭代器呢

迭代器模式

集合迭代器

java基础(17)集合类(1:Collection)

Java中的迭代器模式

设计模式-迭代器模式