Differenza tra tipo generico e tipo jolly

Sono un novizio in Generic e la mia domanda è: quale differenza tra due funzioni:

funzione 1:

public static  void funct1 (List list1) { } 

funzione 2:

 public static void funct2(List list) { } 

Grazie.

La prima firma dice: lista1 è una lista di Es.

La seconda firma dice: lista è una lista di istanze di qualche tipo, ma non conosciamo il tipo.

La differenza diventa ovvia quando proviamo a cambiare il metodo in modo da prendere un secondo argomento, che dovrebbe essere aggiunto alla lista all’interno del metodo:

 import java.util.List; public class Experiment { public static  void funct1(final List list1, final E something) { list1.add(something); } public static void funct2(final List list, final Object something) { list.add(something); // does not compile } } 

Il primo funziona bene. E non puoi cambiare il secondo argomento in qualcosa che verrà effettivamente compilato.

In realtà ho appena trovato una dimostrazione ancora più bella della differenza:

 public class Experiment { public static  void funct1(final List list) { list.add(list.get(0)); } public static void funct2(final List list) { list.add(list.get(0)); // !!!!!!!!!!!!!! won't compile !!!!!!!!! } } 

Uno potrebbe come perché abbiamo bisogno di Quando limita solo ciò che possiamo fare con esso (come ha fatto @Babu_Reddy_H nei commenti). Vedo i seguenti vantaggi della versione con caratteri jolly:

  • Il chiamante deve conoscere meno l’object che ha inserito. Ad esempio, se ho una mappa degli elenchi: Map> Posso passare i suoi valori alla tua funzione senza specificare il tipo di elementi della lista. Così

  • Se distribuisco oggetti parametrizzati in questo modo, limito triggersmente ciò che le persone sanno di questi oggetti e ciò che possono fare con esso (a patto che rimangano lontani da un casting non sicuro).

Questi due hanno un senso quando li unisco: List List . Ad esempio, considera un metodo List merge(List, List) , che unisce i due elenchi di input a un nuovo elenco di risultati. Certo, potresti introdurre altri due parametri di tipo, ma perché vorresti? Sarebbe finita di specificare le cose.

  • infine i caratteri jolly possono avere limiti inferiori, quindi con le liste puoi far funzionare il metodo add , mentre get non ti dà nulla di utile. Ovviamente questo fa scattare la domanda successiva: perché i generici non hanno limiti inferiori?

Per una risposta più approfondita vedi: Quando usare i metodi generici e quando usare la wild-card? e http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203

Generics rende la raccolta più sicura.

List : E qui è il parametro di tipo, che può essere utilizzato per determinare il tipo di contenuto dell’elenco, ma non c’era modo di verificare quale fosse il contenuto durante il runtime .

 Generics are checked only during compilation time. 

: Questo è stato appositamente compilato in java, per gestire il problema che era con il parametro Type. "? extends String" significa che questo elenco può avere

 objects which IS-A String. 

Ad esempio:

Classe di cane La class di cane estende la class di tigre animale estende animale

Quindi l’uso di "public void go(ArrayList a)" NOT accept Dog o Tiger come contenuto ma come animale.

"public void go(ArrayList a)" è ciò che è necessario per fare in modo che ArrayList take in Dog and Tiger type. il ArrayList take in Dog and Tiger type.

Controlla i riferimenti in Head First Java.

Il primo è una funzione che accetta un parametro che deve essere un elenco di elementi di tipo E.

il secondo tipo di esempio non è definito

 List list 

in modo da poter passare la lista di qualsiasi tipo di oggetti.

L’elenco come tipo di parametro indica che il parametro deve essere un elenco di elementi con qualsiasi tipo di object. Inoltre, è ansible associare il parametro E per dichiarare riferimenti a voci di elenco all’interno del corpo della funzione.

L’Elenco come un tipo di parametro ha la stessa semantica, tranne per il fatto che non esiste un modo per dichiarare riferimenti agli elementi nell’elenco diverso da quello di usare Object . Altri post danno ulteriori sottili differenze.

Di solito spieghiamo la differenza tra < E > e < ? > da un confronto con quantificazioni logiche, cioè quantificazione universale e quantificazione esistenziale.

  • corrisponde a “forall E, …”
  • corrisponde a “esiste qualcosa (denotato da) tale che ….”

Pertanto, la seguente dichiarazione generica del metodo significa che, per tutto il tipo di class E , definiamo funct1

 public static  void funct1 (List; list1) { } 

La seguente dichiarazione di metodo generico significa che, per alcune classi esistenti indicate da < ? >, definiamo funct2 .

 public static void funct2(List list) { } 

(Dal momento che la tua modifica) Quelle due firme di funzioni hanno lo stesso effetto per il codice esterno – entrambi accettano qualsiasi List come argomento. Un jolly equivale a un parametro di tipo che viene utilizzato una sola volta.

Oltre a quelle differenze menzionate in precedenza, c’è anche un’ulteriore differenza: puoi impostare in modo esplicito gli argomenti type per la chiamata del metodo generico:

 List apples = ... ClassName.funct2(apples); // for some reason the compiler seems to be ok // with type parameters, even though the method has none ClassName.funct1(apples); // compiler error: incompatible types: List // cannot be converted to List 

( ClassName è il nome della class che contiene i metodi.)