21

Ideally, it would look like this (the context doesn't matter):

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

But this is not allowed in Java. How can I achieve this behaviour?

Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
user2460978
  • 735
  • 6
  • 19
  • 3
    Due to type erasure, that doesn't even make sense. (as opposed to C#, where it's merely impossible) – SLaks Jun 06 '13 at 19:01
  • How can I achieve something similar then? – user2460978 Jun 06 '13 at 19:03
  • 1
    You can't. What are you trying to do? Consider using encapsulation. – SLaks Jun 06 '13 at 19:04
  • 1
    possible duplicate of [How to make a Java class that implements one interface with two generic types?](http://stackoverflow.com/questions/1297972/how-to-make-a-java-class-that-implements-one-interface-with-two-generic-types) – artbristol Jun 06 '13 at 19:23
  • A traditional way to deal with the desire to do this is to add a view that gets the correct `Iterable`, e.g. a `segments()` view that returns an `Iterable`. – Louis Wasserman Jun 06 '13 at 20:05
  • 2
    how would you decide the ambiguous `for(Object o:yourInteface){}` – ratchet freak Jun 06 '13 at 21:27

8 Answers8

20

Unfortunately you cannot. In Java you cannot have two methods with following signatures:

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

in one class or interface.

Grzegorz Żur
  • 47,257
  • 14
  • 109
  • 105
18

As other said before, this is impossible. Better use delegation instead of multiple implementation like this:

public interface MyInterface {
  Iterable<Point> points();
  Iterable<Segment> segments();
}

So you can iterate using for:

MyInterface my = ...;
for (Point p : my.points()) {
  ...
}
for (Segment s : my.segments()) {
  ...
}
Arne Burmeister
  • 20,046
  • 8
  • 53
  • 94
9

You cannot. Due to type erasure, in the bytecode, and therefore at run time, Iterable<Whatever> becomes Iterable.

So, at run time, your class' prototype would be:

public interface myInterface extends Iterable, Iterable { ... }

Considering that, how do you determine what class was meant to be iterated over?

fge
  • 119,121
  • 33
  • 254
  • 329
5

As a possible workaround, you could create interfaces for the iterations you want.

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

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

It's not ideal, but would be passable as long as you had a limited number of things you wanted to iterate over.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
greedybuddha
  • 7,488
  • 3
  • 36
  • 50
  • 1
    I was guessing he wanted polymorphism, how does this provide that, you still have two different types (more confusion than criticism). – arynaq Jun 06 '13 at 19:07
  • 1
    This allows him to have a class that implements multiple iterators as they have different method names. It does not allow him to use polymorphism as the same method signature with different return types is not allowed – greedybuddha Jun 06 '13 at 19:09
  • 1
    That's not really helpful. It wont work in a posh for loop or any reasonable methods. – Tom Hawtin - tackline Jun 06 '13 at 19:32
  • It's not ideal, but given what he wants to do it will work, and you can always use the nice looking `while (iter.hasNext())` – greedybuddha Jun 06 '13 at 19:35
3

Others have said it is impossible. They are wrong. It is possible, but probably not what you want.

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

If what you are iterating extends both point and segment this will work. Otherwise Type Erasure means this won't work.

emory
  • 10,725
  • 2
  • 30
  • 58
  • The type erasure of `T` here is just `Point`, not a combination of `Point` and `Segment`. Quoting Angelika Langer's Generics FAQ: "Type Erasure. The leftmost upper bound is used for type erasure and replaces the type parameter in the byte code." So, at runtime, you have an `Iterable`. – Eric Jablow Jun 06 '13 at 22:10
  • At runtime, `MyInterface` would only be treated as an `Iterable`. – Eric Jablow Jun 07 '13 at 00:04
  • Think about this logically: what *is-a* `Point` *and* a `Segment`? It doesn't really make sense. – wchargin Jun 07 '13 at 01:03
  • @WChargin, if we are talking geometry, then a segment with length zero would also be a point. I don't think such a concept is useful, but the OP didn't specify much. So I will assume it is useful in his/her domain. – emory Jun 07 '13 at 03:14
2

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

A class may not at the same time be a subtype of two interface types which are different invocations of the same generic interface (§9.1.2), or a subtype of an invocation of a generic interface and a raw type naming that same generic interface, or a compile-time error occurs.

ZhongYu
  • 19,446
  • 5
  • 33
  • 61
2

Instead of inheriting from the iterable types, try something like this:

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

Then when you want to iterate, it's simply a matter of:

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

This is a pretty common practice, as seen in the Java Collections class.

fluffy
  • 5,212
  • 2
  • 37
  • 67
0

You can also consider creating common interface, superclass or wrapper for Point and Segment and use it as a generic parameter.

Marcin Jedynak
  • 3,697
  • 2
  • 20
  • 19