2010-05-20 17 views
5

Navigando attraverso le biblioteche Guava ho visto questa firma strano su un metodo readlines dalla classe Files:Java tipo strano ritorno generico

public static <T> T readLines(File file, 
          Charset charset, 
          LineProcessor<T> callback) 

Conosco un po 'di farmaci generici in Java, ma questo mi ha sconcertato.

Che cosa significa la doppia T qui? E perché il primo è tra parentesi angolari?

UPDATE: Grazie per le risposte. Non sono ancora chiaro perché dovrei usare una T all'interno delle parentesi. Perché ad esempio non può essere solo:

public static <> T readLines() 

o

pulibc static <K> T readLines() 

O fa impongono che la stessa lettera deve essere utilizzato la sintassi di Java?

Ora this è ancora wierder:

static <T> void fromArrayToCollection(T[] a, Collection<T> c) { 

come può un metodo di avere un tipo generico-ritorno e annullate?

+0

La parentesi angolare T in NON è il tipo di ritorno; è il parametro di tipo per il metodo. –

+0

Si noti che se non era presente nelle firme precedenti, il compilatore si aspetterebbe naturalmente di trovare "class T {...}" definita da qualche parte. Qualcosa deve informare il compilatore che vorresti che ci fosse un parametro * di tipo * chiamato T. E questo è il modo. –

risposta

3

Non sono ancora chiaro perché dovrei usare una T all'interno delle parentesi. Perché ad esempio non può essere solo:

public static <> T readLines() 

o

public static <K> T readLines() 

O fa impongono che la stessa lettera deve essere utilizzato la sintassi di Java?

Il <T> o <K> è il parametro di tipo. Se scrivi <K> T, allora T non è un parametro di tipo - piuttosto, stai utilizzando lo specifico class T. Ciò non funzionerà se non si dispone di una classe che è letteralmente denominata T nell'ambito.

Ora, questo è ancora wierder:

static <T> void fromArrayToCollection(T[] a, Collection<T> c) { 

come può un metodo di avere un tipo generico-ritorno e annullate?

Non funziona; il <T> non è un "tipo di ritorno generico", è solo il parametro di tipo del metodo. Stai dicendo che il metodo è generico e T è il parametro type. Il tipo di reso del metodo è void.

+0

Questa è la frase che stavo cercando: "Stai dicendo che il metodo è generico e T è il parametro del tipo". Grazie! – drozzy

7

Il primo T all'interno delle parentesi angolari significa che il metodo stesso è generico. Il secondo T è il tipo di ritorno. T può essere di qualsiasi tipo entro i suoi limiti. In questo caso, T non ha limiti.

T sarà determinato nel sito di chiamata e, in questo caso, dedotto dal parametro LineProcessor <T>.

9

Si tratta di un metodo generico - il T è chiamato un tipo di parametro , e può rappresentare qualsiasi tipo. Quindi, se ho un metodo con questa firma:

public <T> T foo(T[] bar) 

mi può chiamare in qualsiasi array, e restituirà un singolo oggetto dello stesso tipo. Se gli passo un array String, tornerò una stringa, e così via. Maggiori informazioni in the Sun tutorials for "generic methods".

Edit: In risposta alla tua domanda aggiornato, tenere a mente che la prima <T>non è parte del tipo di ritorno: è solo un indicatore che T è un parametro di tipo. Così guardare l'esempio che hai citato:

static <T> void fromArrayToCollection(T[] a, Collection<T> c) 

Questo significa solo che fromArrayToCollection accetterà alcuna matrice e qualsiasi raccolta, ma che devono essere un array e la raccolta dello stesso tipo. Quindi puoi passare in uno String[] e uno Collection<String> o uno Integer[] e uno Collection<Integer>, ma non unoe uno Collection<Integer>. Indipendentemente dal tipo che hai inserito per T, il metodo non restituisce nulla.

+0

Grazie, guarda l'aggiornamento alla mia domanda – drozzy

0

Questo è un metodo generico.

In realtà ci sono tre Ts, la terza a LineProcessor<T> specifica T quando si utilizza il metodo.

3

Invece di essere generico a livello di classe, solo il metodo readLines utilizza i generici.

  • Il primo <T> dichiara i tipi generici utilizzati dal metodo
  • Il seguente T è il tipo di ritorno.

Il primo utilizza la stessa sintassi di una classe generica per dichiarare i tipi generici. Invece si potrebbe scrivere

class Generic <T> 
{ 
public static T readLines(File file, 
          Charset charset, 
          LineProcessor<T> callback) 
} 

Questo però renderebbe tutte le istanze della classe generica.

Esempio Esteso:

public static <ElementType,ListType extends List<ElementType>> ListType add(ListType list,ElementType elem) 
{ 
    list.add(elem); 
    return list; 
} 
ArrayList<String> = add(add(new ArrayList<String>(),"Hello"),"World"); 

Il metodo aggiunge un dato elemento a un elenco e restituisce la lista.
Il metodo utilizza due tipi generici uno per gli elementi dell'elenco e uno per l'elenco stesso.
I nomi utilizzati non sono niente di speciale, usare una T per un tipo generico è come usare i per un intero.

  • ElementType è il nome usato per il generico tipo degli elementi (qualsiasi nome/identificatore di variabile valido potrebbe essere usato)
  • ListType è il nome per il tipo di elenco generico, le classi utilizzate devono estendersi/implementare List per ElementType.

L'esempio chiama il metodo con:

  • ElementType = stringa
  • ListType = ArrayList

che comporterebbe
public static ArrayList<String> add(ArrayList<String> list, String elem)

fine gonfiamento :-)

+0

Grazie, questo lo rende più chiaro ... ma perché devo usare una lettera "T" all'interno delle parentesi anziché, ad esempio, la lettera "K" o "B" o nessuna a tutto (cioè solo parentesi vuote). – drozzy

+0

La lettera T è solo un nome, i nomi tra < and > dichiarano solo nomi per i tipi generici utilizzati. È possibile dichiarare un metodo con 3 tipi generici come questo statico pubblico ExtraType someMethod (TypeA var1, AnOtherTypeB var2, ExtraType var3). – josefx

Problemi correlati