2013-06-06 2 views
19

Im Idealfall würde es so aussehen, (der Kontext keine Rolle spielt):Wie mache ich eine Java-Schnittstelle, die Iterable mit zwei verschiedenen generischen Typen erweitert?

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

Aber in Java ist nicht erlaubt. Wie kann ich dieses Verhalten erreichen?

+3

Aufgrund der Art des Löschens ist das nicht einmal sinnvoll. (im Gegensatz zu C#, wo es einfach unmöglich ist) – SLaks

+0

Wie kann ich dann etwas ähnliches erreichen? – user2460978

+1

Sie können nicht. Was versuchst du zu machen? Erwägen Sie die Verwendung von Kapselung. – SLaks

Antwort

18

Leider können Sie nicht. In Java können Sie nicht zwei Methoden mit folgenden Signaturen verwenden:

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

in einer Klasse oder Schnittstelle.

+1

Was wäre, wenn eine der iterator() -Methoden einen Parameter hätte? – user2460978

+0

Zum Beispiel "Comparable , Comparable " es würde auch nicht funktionieren, weil es zweimal die Implementierung Schnittstelle verletzen würde, siehe @fge Antwort. Eigentlich habe ich eine Konsequenz der Implementierung Schnittstelle zweimal, –

+0

Ich frage mich, ob Sie dies haben können: Iterator iterator(); Iterator Iterator (int i); Seit jetzt sind die Signaturen unterschiedlich. – user2460978

9

Sie können nicht. Aufgrund von Typlöschung wird im Bytecode und damit zur Laufzeit Iterable<Whatever> zu Iterable.

Also, zur Laufzeit, die Klasse Prototyp wäre:

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

Anbetracht dessen, dass, wie Sie bestimmen, welche Klasse sein sollte iteriert?

5

Als eine mögliche Problemumgehung können Sie Schnittstellen für die gewünschten Iterationen erstellen.

Es ist nicht ideal, aber würde passierbar sein, solange Sie eine begrenzte Anzahl von Dingen hatten, über die Sie iterieren wollten.

+1

Ich vermutete, er wollte Polymorphie, wie sieht das aus, Sie haben immer noch zwei verschiedene Arten (mehr Verwirrung als Kritik). – arynaq

+1

Dies ermöglicht ihm eine Klasse, die mehrere Iteratoren implementiert, da sie unterschiedliche Methodennamen haben. Es erlaubt ihm nicht, Polymorphie zu verwenden, da die gleiche Methodensignatur mit verschiedenen Rückgabetypen nicht erlaubt ist – greedybuddha

+1

Das ist nicht wirklich hilfreich. Es funktioniert nicht in einer schicken Schleife oder irgendeiner vernünftigen Methode. –

0

Sie können auch eine allgemeine Schnittstelle, Superklasse oder einen Wrapper für Punkt und Segment erstellen und als generischen Parameter verwenden.

16

Wie bereits erwähnt, ist dies unmöglich. Bessere Nutzung Delegation statt mehrerer Umsetzung wie folgt aus:

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

So können Sie mit für iterieren:

MyInterface my = ...; 
for (Point p : my.points()) { 
    ... 
} 
for (Segment s : my.segments()) { 
    ... 
} 
2

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

Eine Klasse kann zugleich nicht ein Untertyp von zwei Schnittstellentypen, die verschiedene Aufrufe derselben generischen Schnittstelle sind (§9.1.2), oder ein Subtyp eines Aufrufs einer generischen Schnittstelle und einer Rohdatei Geben Sie die Benennung derselben generischen Schnittstelle ein, oder es tritt ein Fehler bei der Kompilierung auf.

3

Andere haben gesagt, dass es unmöglich ist. Sie liegen falsch. Es ist möglich, aber wahrscheinlich nicht das, was Sie wollen.

Wenn das, was Sie iterieren, sowohl Punkt als auch Segment erweitert, wird dies funktionieren. Andernfalls bedeutet Type Erasure, dass dies nicht funktioniert.

+0

Die Art Löschung von 'T' hier ist nur' Point', nicht eine Kombination aus "Point" und "Segment". Zitat von Angelika Langers Generics FAQ: "Type Erasure. Die obere Grenze ganz links wird zum Löschen von Typen verwendet und ersetzt den Typ-Parameter im Byte-Code." Zur Laufzeit haben Sie also ein 'Iterable '. –

+0

@EricJablow Ich bin mir nicht sicher, was dein Standpunkt ist. – emory

+0

Zur Laufzeit wird 'MyInterface' nur als' Iterable ' behandelt. –

2

Statt von den iterable Arten von vererben, versuchen, etwas wie folgt aus:

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

Dann, wenn Sie iterieren wollen, ist es nur eine Frage der:

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

Dies ist eine ziemlich gängige Praxis ist, , wie in der Java-Collections-Klasse zu sehen.

+0

Hoppla, habe oben die Antwort von Arne Burmeister nicht gesehen, die dem gleichen Grundmuster folgt. – fluffy

Verwandte Themen