如何使用两种不同的泛型扩展Iterable的Java接口



理想情况下,它应该是这样的(上下文无关紧要):

public interface myInterface extends Iterable<Point>, Iterable<Segment> { ... }

但是在Java中是不允许的。我怎样才能达到这种行为呢?

遗憾的是,您不能。在Java中,不能有两个具有以下签名的方法:

Iterator<Point> iterator();
Iterator<Segment> iterator();

如前所述,这是不可能的。最好使用委托而不是像这样的多重实现:

public interface MyInterface {
  Iterable<Point> points();
  Iterable<Segment> segments();
}
所以你可以用来迭代:
MyInterface my = ...;
for (Point p : my.points()) {
  ...
}
for (Segment s : my.segments()) {
  ...
}

不能。由于类型擦除,在字节码中,因此在运行时,Iterable<Whatever>变为Iterable

所以,在运行时,你的类的原型将是:
public interface myInterface extends Iterable, Iterable { ... }

考虑到这一点,如何确定要迭代哪个类呢?

作为一种可能的解决方案,您可以为您想要的迭代创建接口。

public interface SegmentIterable{
    public Iterator<Segment> segmentIterator();
}
public interface PointIterable{
    public Iterator<Point> pointIterator();
}

这并不理想,但只要您想迭代的内容有限,就可以通过。

其他人说这是不可能的。他们错了。这是可能的,但可能不是你想要的。

public interface MyInterface<T extends Point & Segment> extends Iterable<T>
{
}

如果你的迭代扩展了点和段,这将有效。

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.1.5

一个类不能同时是两个接口类型的子类型,这两个接口类型是同一泛型接口的不同调用(§9.1.2),或者是一个泛型接口调用的子类型和命名同一泛型接口的原始类型,否则会发生编译时错误。

与其继承可迭代类型,不如试试这样做:

public interface MyInterface {
    public Iterable<Point> asPoints() { ... }
    public Iterable<Segment> asSegments() { ... }
}

当你想迭代时,只需:

for (Point p : myClass.asPoints()) {
    ...
}

这是一种非常常见的做法,就像在Java Collections类中看到的那样。

您还可以考虑为Point和Segment创建通用接口、超类或包装器,并将其用作泛型参数。

最新更新