"Ciao, Amico!"

"Ciao, Eli!"

"Oggi io e Rishi vi parleremo dei farmaci generici."

"Aspetta, penso di sapere già quasi tutto."

"Quasi tutto, ma non tutto."

"Davvero? OK, sono pronto ad ascoltare."

"Allora cominciamo."

"In Java, i generici sono classi che hanno parametri di tipo."

"Per quanto riguarda il motivo per cui sono stati inventati i generici, vedere i commenti nel codice:"

Esempio
ArrayList stringList = new ArrayList();
stringList.add("abc"); // Add a string to the list
stringList.add("abc"); // Add a string to the list
stringList.add( 1 ); // Add a number to the list

for(Object o: stringList)
{
 String s = (String) o; // There will be an exception here when we get to the integer
}

Come risolvere il problema utilizzando Generics:

Esempio
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("abc"); // Add a string to the list
stringList.add("abc"); // Add a string to the list
stringList.add( 1 ); // There will be a compilation error here

for(Object o: stringList)
{
 String s = (String) o;
}

"Questo codice semplicemente non verrà compilato e l'errore causato dall'aggiunta del tipo di dati errato verrà notato durante la compilazione."

"Sì, questo lo so già."

"Va bene, bene. La ripetizione è la madre dell'apprendimento."

"Ma i creatori di Java sono stati un po' pigri quando hanno creato i generici. Invece di creare tipi completi con parametri, sono scivolati in un'ottima ottimizzazione. In realtà, non hanno aggiunto alcuna informazione sui parametri di tipo ai generici. Invece, tutte le la magia si verifica durante la compilazione."

Codice con generici
List<String> strings = new ArrayList<String>();
strings.add("abc");
strings.add("abc");
strings.add( 1); // Compilation error

for(String s: strings)
{
 System.out.println(s);
}
Cosa succede davvero
List strings = new ArrayList();

strings.add((String)"abc");
strings.add((String)"abc");
strings.add((String) 1); // Compilation error

for(String s: strings)
{
 System.out.println(s);
}

"Questo è perfetto."

"Sì, ma questo approccio ha un effetto collaterale.  Nessuna informazione sui parametri di tipo viene memorizzata all'interno di una classe generica.  Questo approccio in seguito divenne noto come type erasure ."

"In altre parole, se hai la tua classe con parametri di tipo, non puoi utilizzare le informazioni su di essi all'interno della classe."

Codice con generici
class Zoo<T>
{
 ArrayList<T> pets = new ArrayList<T>();

 public T createAnimal()
 {
  T animal = new T();
  pets.add(animal)
  return animal;
 }
}
Cosa succede davvero
class Zoo
{
 ArrayList pets = new ArrayList();

 public Object createAnimal()
 {
  Object animal = new ???();
  pets.add(animal)
  return animal;
 }
}

"Durante la compilazione, tutti i tipi di parametro vengono sostituiti con Object. E all'interno della classe non ci sono informazioni sul tipo passato ad essa."

"Sì, sono d'accordo, non è il massimo."

"Non è così spaventoso. Ti dirò più tardi come aggirare questo problema."

Ma c'è di più. Java consente di specificare un tipo padre per i parametri di tipo. La parola chiave extends viene utilizzata per questo. Per esempio:

Codice con generici
class Zoo<T extends Cat>
{
 T cat;

 T getCat()
 {
  return cat;
 }

 void setCat (T cat)
 {
  this.cat = cat;
 }

 String getCatName()
 {
  return this.cat.getName();
 }
}
Cosa succede davvero
class Zoo
{
 Cat cat;

 Cat getCat()
 {
  return cat;
 }

 void setCat(Cat cat)
 {
  this.cat = cat;
 }

 String getCatName()
 {
  return this.cat.getName();
 }
}

"Nota due fatti:"

"In primo luogo, non puoi passare qualsiasi tipo come parametro: puoi solo passare un Cat o una classe che eredita Cat."

"In secondo luogo, all'interno della classe Zoo, le variabili di tipo T possono ora chiamare i metodi della classe Cat.  La colonna a destra spiega perché (perché Cat verrà sostituito ovunque ci sia una T)"

"Sì. Se diciamo che Cat o una sottoclasse di Cat viene passata come argomento di tipo, allora siamo certi che il tipo T avrà sempre i metodi della classe Cat."

"Beh, è ​​intelligente."