java iterator/iterable subinterface

依然范特西╮ 提交于 2019-12-05 17:56:31

The concrete class compiles fine because B extends A, and since Java 5 a return type on a subclass can be a subclass of the return type on the superclass.

As for the generic, I have hit the same wall, and you have two options that I know of.

One is to paramaterize A:

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

then:

public class B implements A<B>

However, that has a disadvantage that you will need to give a parameter of A, instead of having it fixed, even if you want A:

private class NoOneSees implements A<A>

As to the question of if you actually want Iterator<B>, in the case of an Iterable, most likely that is preferable, and considering that these are interfaces, the need to redeclare the parameter is probably reasonable. It gets a little more complicated if you start inheriting concrete classes, and for things that have meaning other than an Iterable, where you may want covariance. For example:

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.
}

Similarly for covariance, you can't declare a variable of type Iterator<A> and then assign an Iterator<B> in it, even if B extends A.

The other option is live with the fact that further implementation/subclasses will still reference A.

Carl was right, my first answer didn't compile but this seems to. Not sure if it's what you want exactly.

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

}

public class B implements A<B> {

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

The other answers have the right gist - but you'll get the right mechanics by declaring the generic type as

A<T extends A<T>>

This forces a class to return an iterator that is of its own type or lower - so you would be able to declare

class B implements A<B>

but not

class B implements A<A>

which I suspect is closer to what you want (i.e. implementations must return iterators over themselves, rather than simply over As).

Note that your experiences with Iterator vs Iterable stem from the lack of covariance of generic types; an instance of B is an A, but an Iterator<B> is not an Iterator<A>.

I guess this is what you want:

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

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

Your design decisions are your own, but I can't think of any reason for EVERY class in a design to implement Iterable. There must be some kind of thing that is contained in a collection but isn't actually a collection itself. I would take a long hard look at the fundamental design. Maybe some iterables will want to return iterators of things that are not related to themselves.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!