2013-06-06 9 views
19

Idealmente, sarebbe simile a questa (il contesto non ha importanza):Come creare un'interfaccia Java che estenda Iterable con due diversi tipi generici?

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

Ma questo non è consentito in Java. Come posso ottenere questo comportamento?

+3

A causa della cancellazione del tipo, ciò non ha nemmeno senso. (al contrario di C#, dove è semplicemente impossibile) – SLaks

+0

Come posso ottenere qualcosa di simile allora? – user2460978

+1

Non puoi. Cosa stai cercando di fare? Prendi in considerazione l'utilizzo dell'incapsulamento. – SLaks

risposta

18

Purtroppo non è possibile. In Java non è possibile avere due metodi con le seguenti firme:

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

in una classe o interfaccia.

+1

E se uno dei metodi iterator() avesse un parametro? – user2460978

+0

Ad esempio 'Comparable , Comparable ' non funzionerebbe neanche perché violerebbe l'interfaccia di implementazione due volte, vedere risposta @fge. In realtà ho mostrato una conseguenza dell'interfaccia di implementazione due volte, –

+0

Mi chiedo se si può avere questo: iteratore iteratore(); Iterator iteratore (int i); Da oggi le firme sono diverse. – user2460978

9

Non è possibile. A causa della cancellazione dei tipi, nel bytecode e quindi in fase di esecuzione, Iterable<Whatever> diventa Iterable.

Quindi, in fase di esecuzione, prototipo di classe sarebbe:

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

Considerando che, come si fa a determinare quale classe è stato pensato per essere iterata finita?

5

Come soluzione alternativa, è possibile creare interfacce per le iterazioni desiderate.

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

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

Non è l'ideale, ma sarebbe percorribile fino a quando si ha un numero limitato di cose che si desidera ripetere.

+1

Immaginavo che volesse il polimorfismo, in che modo questo fornisce ciò, hai ancora due tipi diversi (più confusione che critiche). – arynaq

+1

Ciò gli consente di avere una classe che implementa più iteratori in quanto hanno nomi di metodi diversi. Non gli consente di utilizzare il polimorfismo poiché la stessa firma del metodo con tipi di ritorno diversi non è consentita. – greedybuddha

+1

Non è molto utile. Non funzionerà in un elegante ciclo o in qualsiasi metodo ragionevole. –

0

È inoltre possibile considerare la creazione di un'interfaccia, una superclasse o un wrapper comuni per Punto e Segmento e utilizzarlo come parametro generico.

16

Come detto in precedenza, questo è impossibile. Meglio utilizzare la delega al posto di molteplici applicazione in questo modo:

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

Così si può iterare utilizzando per:

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

Una classe non può allo stesso tempo essere un sottotipo di due tipi di interfaccia che sono invocazioni diverse della stessa interfaccia generica (§9.1.2), o un sottotipo di una chiamata di un'interfaccia generica e un grezzo digita il nome della stessa interfaccia generica o si verifica un errore in fase di compilazione.

3

Altri hanno detto che è impossibile. Si sbagliano. È possibile, ma probabilmente non è quello che vuoi.

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

Se ciò che stai iterando estende sia il punto che il segmento, funzionerà. Altrimenti, Type Erasure significa che questo non funzionerà.

+0

Il tipo cancellato da 'T' qui è solo' Punto', non una combinazione di 'Punto' e' Segmento'. Citazione delle FAQ di Angelika Langer su Generics: "Type Erasure. Il limite superiore più a sinistra viene utilizzato per la cancellazione dei tipi e sostituisce il parametro type nel codice byte." Quindi, in fase di esecuzione, si ha un 'Iterable '. –

+0

@EricJablow Non sono sicuro di quale sia il tuo punto. – emory

+0

In fase di esecuzione, 'MyInterface' viene considerato come' Iterable '. –

2

Invece di ereditare dai tipi iterabili, provare qualcosa di simile:

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

Poi, quando si vuole iterare, è semplicemente una questione di:

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

Questa è una pratica abbastanza comune , come visto nella classe Collections di Java.

+0

Oops, non ho visto la risposta di Arne Burmeister sopra, che segue lo stesso schema di base. – fluffy

Problemi correlati