2011-01-14 15 views
9

Sto leggendo "Generics in Java Programming Language" di Gilad Bracha e sono confuso riguardo uno stile di dichiarazione. Il seguente codice si trova a pagina 8:Qualcuno può spiegare la dichiarazione di questi metodi generici java?

interface Collection<E> 
{ 
    public boolean containsAll(Collection<?> c); 
    public boolean addAll(Collection<? extends E> c); 
} 


interface Collection<E> 
{ 
    public <T> boolean containsAll(Collection<T> c); 
    public <T extends E> boolean addAll(Collection<T> c); 
    // hey, type variables can have bounds too! 
} 

Il mio punto di confusione deriva dalla seconda dichiarazione. Non è chiaro per me quale sia lo scopo della dichiarazione <T> serve nella seguente riga:

public <T> boolean containsAll(Collection<T> c); 

Il metodo è già un tipo (booleano) ad esso associati.

Perché utilizzare lo <T> e cosa indica al compilatore?

Penso che la mia domanda debba essere un po 'più specifica.

Perché si scrivere:

public <T> boolean containsAll(Collection<T> c); 

vs

public boolean containsAll(Collection<T> c); 

Non è chiaro per me, quale sia lo scopo di <T> è, nella prima dichiarazione di containsAll.

+1

Se capisci il PECS, allora capirai questi. Controlla qui http://stackoverflow.com/questions/4535930/regarding-pecs-java-generics –

+1

In Oracle/Sun JDK 6, viene utilizzato il primo esempio, quindi non so che useresti anche il secondo. –

+1

E perché è meglio di 'public boolean containsAll (Collection c);'? –

risposta

3

Per quanto ne so, in questo caso <T> non fornisce nulla di utile.Crea un metodo che è completamente funzionalmente equivalente a quelli che utilizzano invece il carattere jolly.

Ecco un paio di esempi in cui si sarebbe essere utili:

public List<?> transform(List<?> in); 
//vs 
public <T> List<T> transform(List<T> in); 

In quanto sopra, è possibile correlare il tipo di ritorno con il tipo di ingresso. Il primo esempio non può correlare il tipo di runtime dei due caratteri jolly.

public void add(List<?> list, Object obj); 
//vs 
public <T> void add(List<? super T> list, T obj); 

In quanto precede, il primo metodo non sarà anche in grado di aggiungere obj a list in quanto non può essere considerato sicuro tipo. Il parametro generico nel secondo assicura che list possa contenere qualsiasi tipo di obj.

3

Il metodo ha già un tipo (booleano) associato.

Questa è la ritorno tipo. Il tipo completo del metodo è "metodo che accetta un parametro Collection<T> (per alcuni T) e restituisce un valore boolean".

ed è qui che viene in T: il parametro della funzione lo utilizza. In altre parole, questo metodo può essere chiamato con diversi tipi come argomento. L'unica limitazione di questi tipi è che devono implementare l'interfaccia Collection<T>, che a sua volta si basa su un argomento generico T (il tipo di oggetti memorizzati nella raccolta).

+0

Ma perché è meglio l'equivalente apparentemente funzionale 'public boolean containsAll (Collection c)'? Allo stesso modo, perché non? Public booleano addAll (Collection c) '? –

+0

È meglio perché il corpo o la definizione del metodo possono riferirsi al tipo T, e il codice può evitare il cast e essere garantito dal compilatore in base al tipo. Vedi la mia risposta per ulteriori spiegazioni. –

+0

@Dave Costa: Non vedo una risposta da te, ma se usare '' aiuta ** altri ** metodi è irrilevante. Stiamo parlando di ** questi ** metodi, in cui non sembra offrire alcun beneficio. –

0

Provare a compilarlo senza il <T>.

Fondamentalmente, sta dicendo al compilatore che questo metodo contiene un generico. Non è richiesto nel primo esempio perché? è un caso speciale e il secondo metodo fa riferimento al tipo definito nell'interfaccia stessa.

Su una nota non correlata, il pubblico non è richiesto in un'interfaccia. I metodi in un'interfaccia sono pubblici per impostazione predefinita, quindi puoi risparmiare un po 'di digitazione.

0

Dichiara il tipo generico T utilizzato dal metodo. Mentre il tipo generico E è lo stesso per l'intera interfaccia T è limitato al metodo per cui è stato dichiarato.

2

Il? è semplicemente un jolly. Significa che il metodo accetterà una raccolta di qualsiasi tipo.

Il <T> è un parametro di tipo per il metodo. Assegna essenzialmente al carattere jolly un nome che può quindi essere indirizzato altrove nella dichiarazione e nella definizione del metodo.

Una migliore spiegazione della differenza sarebbe se il tipo di ritorno del metodo variava in base al tipo che è stato passato in.

Diciamo che iniziare con un metodo come

Object getRandomElement(Collection<?> c)

Questo accetterà qualsiasi raccolta, ma non è possibile vincolarne il tipo di ritorno. Quindi un chiamante dovrebbe restituire il risultato a qualunque tipo si aspettasse, il che dovrebbe funzionare, ma solleva avvisi di conversione del tipo non sicuri.

Con un parametro di tipo si potrebbe invece scrivere

<T> T getRandomElement(Collection<T> c)

In questo caso, se si chiama questo metodo con un Collection<String>, il compilatore sa che restituirà un String.

+0

Ben detto. Penso che una buona regola è che il parametro type è richiesto solo quando si ha un tipo di ritorno parametrizzato (come 'Collections.emptyList() ') o quando è necessario correlare il tipo restituito o un altro parametro con un parametro parametrico o generico. –

Problemi correlati