2013-05-07 18 views
7

Come da una letteratura che ho letto, che abbiamo frutti succosi implementign la seguente interfaccia:delimitata metodo generico di tipo 'super'

public interface Juicy<T> { 
    Juice<T> squeeze(); 
} 

Utilizzando le variabili di tipo limitati, seguendo il metodo sarebbe TAKS un mucchio di frutti e li spremere tutti:

<T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits); 

Ora abbiamo bisogno di fratelli minori, come di seguito lavorare troppo:

class Orange extends Fruit implements Juicy<Orange>; 
class RedOrange extends Orange; 

Così si aspetterebbe il metodo di guardare il seguente:

<T extends Juicy<T>> List<Juice<? super T>> squeeze(List<? extends T> fruits); 

Invece trovo la firma del metodo per essere come di seguito:

<**T extends Juicy<? super T>>** List<Juice<? super T>> squeezeSuperExtends(List<? extends T> fruits); 

Come si spiega questa differenza?

+0

Non dovrebbe essere 'interfaccia pubblica Juicy >'? (per evitare 'classe Orange estende Fruit implementa Juicy ') – SLaks

+0

@SLaks: Non è un guadagno enorme, come se 'Apple' implementato' Juicy 'quindi il caso che menzionate non sarebbe stato prevenuto. –

+0

@ MarkPeters: hai ragione; non c'è modo di impedirlo. Tuttavia, impedirebbe 'classe Orange estende Fruit implementa Juicy ' – SLaks

risposta

3

Il <? super T> all'interno <T extends Juicy<? super T>> c'è modo che RedOrange, che è una sottoclasse di Juicy<Orange> può essere all'interno del suo limite.

immaginare senza la prima <? super T>:

public <T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits) {... 

Ora T deve essere un Juicy<T>. La classe Orange è una Juicy<T>, è una Juicy<Orange>. Ma la classe RedOrange non è una Juicy<T>. Non è un Juicy<RedOrange>; è un Juicy<Orange>. Così, quando si cerca di chiamare squeeze:

List<RedOrange> redOranges = new ArrayList<RedOrange>(); 
List<Juice<RedOrange>> juices = squeeze(redOranges); 

otteniamo il seguente errore del compilatore:

Inferred type 'RedOrange' for type parameter 'T' is not within its bound; should implement 'Juicy<RedOrange>'. 

Se poniamo la <? super T>, che permette il parametro tipo per Juicy essere una superclasse di T. Ciò consente di utilizzare RedOrange perché è un Juicy<Orange> e Orange è una superclasse a RedOrange.

public <T extends Juicy<? super T>> List<Juice<T>> squeeze(List<T> fruits) {... 

Ora la chiamata a squeeze compila sopra.

EDIT

Ma cosa succede se vogliamo squeeze un List<Juice<Orange>> da un List<RedOrange>? Ha ottenuto un po 'difficile, ma ho trovato una soluzione:

Abbiamo bisogno di un secondo parametro di tipo per abbinare Orange nel metodo squeeze:

public <S extends Juicy<S>, T extends Juicy<S>> List<Juice<S>> squeeze(List<T> fruits) 

Qui, S rappresenta Orange, in modo che possiamo tornare List<Juice<Orange>>.Ora possiamo dire

List<RedOrange> redOranges = new ArrayList<RedOrange>(); 
List<Juice<Orange>> juices = squeeze(redOranges); 
+0

Mi piace questa risposta, ma aiutami a riflettere sul motivo per cui * dovresti * essere in grado di ottenere un 'Elenco >' dal juicing di un 'Elenco '. Un 'RedOrange' produce' Juice ', non' Juice 'quindi il metodo' squeeze' non sarebbe insoddisfacente (cioè impossibile da implementare in modo sicuro/corretto)? –

+1

@ MarkPeters - Interessante. Ho aggiunto un modo per ottenere un 'Elenco >'. – rgettman

+0

Il mio punto è più che Se * puoi * avere una dichiarazione 'Elenco > Succhi = spremere (redOranges)', allora qualcosa è decisamente sbagliato, perché un 'RedOrange' non produce' Succo '. Prova a implementare in sicurezza squeeze. Sospetto che tu non possa. –

3

Mi sembra il modo più semplice di pensare a questo è di ignorare brevemente la relazione tra il tipo di frutta e il tipo di succo di frutta che produce. Tale collegamento è stabilito nella dichiarazione di classe; non ne abbiamo bisogno per spremere un po 'di Juicy s.

In altre parole, solo parametrizzare il tipo di Juice che le Juicy s produrranno:

<T> List<Juice<T>> squeeze(List<? extends Juicy<? extends T>> fruits); 

Qui si produce un elenco di succhi di frutta in base al tipo super-comune di prodotti Juice (cioè il parametro di Juicy), non il comune tipo di frutta.

Poi abbiamo le seguenti:

//works 
List<Juice<Orange>> b = squeeze(Arrays.asList(new Orange(), new RedOrange())); 

//fails as it should 
List<Juice<RedOrange>> d = squeeze(Arrays.asList(new RedOrange())); 
+0

+1, hai una soluzione più semplice per generare un 'Elenco >' di me. – rgettman

+0

+1 per la straordinaria semplicità – IUnknown

Problemi correlati