"Bună! Voi continua lecția lui Ellie despre generice. Ești gata să asculți?"

"Da."

— Atunci să începem.

„Primul lucru pe care trebuie să-l știți este că metodele unei clase pot avea și proprii parametri de tip.”

"Știu."

„Nu, mă refer în special la parametrii lor de tip:

Exemplu
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
}

"Acești parametri de tip se referă în mod special la metode. Clasa nu are parametri. Puteți chiar declara aceste metode statice și le apelați fără un obiect."

"Înțeleg. Punctul parametrilor de tip în metode este același ca pentru clase?"

— Da. Dar e ceva nou.

„După cum știți deja, puteți utiliza un wildcard în declarația de tip. Apoi imaginați-vă următoarea situație:”

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

„Dar dacă vrem să adăugăm un articol nou la colecție:”

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

"Problema este că, în cazul general, metodei doSomething i se poate trece o Listă ale cărei elemente nu sunt obiecte MyClass, ci mai degrabă obiecte din orice subclasă a MyClass. Dar nu puteți adăuga obiecte MyClass la o astfel de listă!"

"Ah. Deci, ce se poate face în privința asta?"

"Nimic. În această situație, nu poți face nimic. Dar asta le-a dat creatorilor Java ceva la care să se gândească. Și au venit cu un nou cuvânt cheie: super ."

„Sintaxa arată aproape la fel:”

List<? super MyClass> list

Dar există o distincție importantă între extinde și super.

„«? extinde T» înseamnă că clasa trebuie să fie un descendent al lui T.”

„«? super T» înseamnă că clasa trebuie să fie un strămoș al lui T.”

"Holy Moly. Deci unde este folosit asta?"

„«? super T» este folosit atunci când o metodă implică adăugarea la o colecție de obiecte T. În acest caz, ar putea fi o colecție de obiecte T sau orice strămoș al lui T."

„Ah. Obiectul AT poate fi atribuit unei variabile de referință al cărei tip este oricare dintre strămoșii lui T”

"Sincer, această abordare nu este folosită foarte des. În plus, are un neajuns. De exemplu:"

Exemple
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.
}

„Acum, primul exemplu nu funcționează”.

„Deoarece lista ar putea fi chiar o List<Object> (Obiectul este superclasa de top a MyClass), în esență scriem următorul cod nevalid:”

Exemplul 1
List<Object> list;

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

— Înțeleg. Mulțumesc pentru lecția interesantă.

"Cu plăcere."