2010-02-22 4 views
17

Uso i generici piuttosto a lungo, ma non ho mai utilizzato la costruzione come List<? super T>.Qualcuno può spiegare che cosa significa "<? super T>" e quando deve essere utilizzato e in che modo questa costruzione dovrebbe cooperare con <T> e <? extends T>?

Che cosa significa? Come usarlo? Come si cura dopo la cancellazione?

Mi chiedo anche: è qualcosa di standard nella programmazione generica (programmazione template?) O è solo un'invenzione java? C#, ad esempio, consente costruzioni simili?

risposta

9

Questo costrutto viene utilizzato quando si desidera consumare elementi da una raccolta in un'altra raccolta. Per esempio. si dispone di un generico Stack e si desidera aggiungere un metodo popAll che accetta una raccolta come parametro e inserisce tutti gli elementi nello stack. Dal buon senso, questo codice dovrebbe essere legale:

Stack<Number> numberStack = new Stack<Number>(); 
Collection<Object> objects = ... ; 
numberStack.popAll(objects); 

ma compila solo se si definisce popAll in questo modo:

// Wildcard type for parameter that serves as an E consumer 
public void popAll(Collection<? super E> dst) { 
    while (!isEmpty()) 
    dst.add(pop()); 
} 

L'altro lato della medaglia è che pushAll dovrebbero essere definite in questo modo:

// Wildcard type for parameter that serves as an E producer 
public void pushAll(Iterable<? extends E> src) { 
    for (E e : src) 
    push(e); 
} 

Aggiornamento: Josh Bloch propaga questo mnemonico per ricordare quale tipo jolly da usare:

PECS acronimo di produttore-estende, consumer-super.

Per ulteriori dettagli, vedere Effective Java 2nd Ed., Item 28.

+0

Java efficace è ottimo, ma non ho ancora la 2a edizione (( – Roman

+0

@Roman è possibile scaricare il capitolo su Generics dal collegamento aggiunto :-) –

+0

Grazie, lo leggerò. ci sono altri 'esempi di capitoli' disponibili gratuitamente? – Roman

4

Questo è chiamato "carattere jolly limitato". È spiegato molto bene in the official tutorial.

Come indicato nel tutorial, si sa quindi che l'elenco contiene oggetti di esattamente un sottotipo di T

Per esempio List<? extends Number> può contenere solo Integer s o solo Long s, ma non entrambi.

+2

' Elenco numeri = Arrays.asList (1,5L); 'compila bene. number' sta tenendo sia Int sia Long. Cosa mi sfugge dall'ultima riga della tua risposta? – Geek

2

Queste cose sono conosciute, in teoria tipo, come varianza, con <? extends T> essendo una notazione co-variante, e <? super T> essendo una notazione contra-variante. La spiegazione più semplice è che ? può essere sostituito da qualsiasi tipo che si estende T nella notazione co-variante, e ? può essere sostituito da qualsiasi tipo che T si estende in quella contro-variante.

L'uso di contromovensione e co è molto più difficile di quanto possa sembrare a prima vista, soprattutto perché la variazione "alterna" a seconda della posizione.

Un semplice esempio potrebbe essere una classe di funzione. Supponiamo che tu abbia una funzione che prende un A e restituisce un B. La notazione corretta per questo sarebbe dire che A è contro-variante e B co-variante.Per capire meglio come questo è il caso, prendiamo in considerazione un metodo - chiamiamola g - che riceve questa ipotetica classe funzione, dove f si suppone di ricevere un Arc2D e restituire una Shape.

All'interno g, questo f è chiamato passando un Arc2D e il valore restituito viene utilizzato per inizializzare un Area (che prevede un Shape).

Ora, supponiamo che lo f che passi riceve uno qualsiasi Shape e restituisce un Rectangle2D. Dal momento che un Arc2D è una anche una Shape, poi g volontà non un errore passando un Arc2D-f, e dal momento che un Rectangle2D è anche un Shape, allora può essere passato al costruttore Area s'.

Se si tenta di invertire una delle varianze o di scambiare i tipi previsti e effettivi in ​​quell'esempio, vedrete che fallisce. In questo momento non ho il tempo di scrivere questo codice, e il mio Java è abbastanza arrugginito, ma vedrò cosa posso fare dopo, se nessuno è così gentile da farlo prima.

0

Le FAQ Java Generics hanno una buona spiegazione sui generici Java. Controlla la domanda What is a bounded wildcard? che spiega l'uso del costrutto "? Super T" in dettaglio.