"Ciao! Continuo la lezione di Ellie sui farmaci generici. Pronta ad ascoltare?"

"SÌ."

"Allora cominciamo."

"La prima cosa che devi sapere è che anche i metodi di una classe possono avere i propri parametri di tipo."

"Lo so."

"No, intendo specificamente i propri parametri di tipo: "

Esempio
class Calculator
{
  T add(T a, T b); // Add
  T sub(T a, T b); // Subtract
  T mul(T a, T b); // Multiply
  T div(T a, T b); // Divide
}

"Questi parametri di tipo riguardano specificamente i metodi. La classe non ha parametri. Potresti persino dichiarare questi metodi statici e chiamarli senza un oggetto."

"Capisco. Il punto dei parametri di tipo nei metodi è lo stesso delle classi?"

"Sì. Ma c'è qualcosa di nuovo."

"Come già sai, puoi usare un carattere jolly nella dichiarazione del tipo. Quindi immagina la seguente situazione:"

Esempio 1
public void doSomething(List<? extends MyClass> list)
{
 for(MyClass object : list)
 {
  System.out.println(object.getState()); // Everything works well here.
 }
}

"Ma cosa succede se vogliamo aggiungere un nuovo elemento alla collezione:"

Esempio 2
public void doSomething(List<? extends MyClass> list)
{
 list.add(new MyClass()); // Error!
}

"Il problema è che nel caso generale al metodo doSomething può essere passato un List i cui elementi non sono oggetti MyClass, ma piuttosto oggetti di qualsiasi sottoclasse di MyClass. Ma non puoi aggiungere oggetti MyClass a tale elenco!"

"Ah. Allora, cosa si può fare?"

"Niente. In questa situazione, non puoi fare nulla. Ma questo ha dato ai creatori di Java qualcosa su cui riflettere. E hanno escogitato una nuova parola chiave: super ."

"La sintassi sembra quasi la stessa:"

List<? super MyClass> list

Ma c'è un'importante distinzione tra extends e super.

"«? estende T» significa che la classe deve essere un discendente di T."

"«? super T» significa che la classe deve essere un'antenata di T."

"Porca miseria. Allora dove si usa?"

"«? super T» viene utilizzato quando un metodo comporta l'aggiunta a una raccolta di oggetti T. In questo caso, potrebbe essere una raccolta di oggetti T o qualsiasi antenato di T."

"Ah. L'oggetto AT può essere assegnato a una variabile di riferimento il cui tipo è uno qualsiasi degli antenati di T"

"Onestamente, questo approccio non viene utilizzato molto spesso. Inoltre, ha un difetto. Ad esempio:"

Esempi
public void doSomething(List<? super MyClass> list)
{
 for(MyClass object : list) // Error!
 {
  System.out.println(object.getState());
 }
}
public void doSomething(List<? super MyClass> list)
{
 list.add(new MyClass()); // Everything works well here.
}

"Ora il primo esempio non funziona."

"Poiché list potrebbe anche essere un List<Object> (Object è la superclasse più in alto di MyClass), stiamo essenzialmente scrivendo il seguente codice non valido:"

Esempio 1
List<Object> list; 

for(MyClass object : list) // Error!
{ 
 System.out.println(object.getState()); 
}

"Capisco. Grazie per l'interessante lezione."

"Prego."