"Bună, Amigo!"

— Bună, Ellie!

„Astăzi, Rishi și cu mine o să vă spunem totul despre medicamente generice.”

— Stai, cred că știu deja aproape totul.

„Aproape totul, dar nu totul”.

"Serios? OK, sunt gata să ascult."

— Atunci să începem.

„În Java, genericele sunt clase care au parametri de tip.”

„În ceea ce privește motivul pentru care au fost inventate genericele, consultați comentariile din cod:”

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

Cum se rezolvă problema folosind generice:

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

„Acest cod pur și simplu nu se va compila, iar eroarea cauzată de adăugarea unui tip de date greșit va fi observată în timpul compilării.”

— Da, știu deja asta.

"Bine, bine. Repetiția este mama învățăturii."

„Dar creatorii Java au fost puțin leneși când au creat generice. În loc să facă tipuri cu drepturi depline cu parametri, au scapat într-o optimizare inteligentă. În realitate, nu au adăugat nicio informație despre parametrii de tip la generice. În schimb, toate magia are loc în timpul compilării.”

Cod cu generice
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);
}
Ce se întâmplă cu adevărat
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);
}

"Asta este slick."

„Da, dar această abordare are un efect secundar.  Nicio informație despre parametrii de tip nu este stocată într-o clasă generică.  Această abordare a devenit ulterior cunoscută sub numele de ștergere a tipului ”.

„Cu alte cuvinte, dacă aveți propria clasă cu parametri de tip, nu puteți folosi informații despre aceștia în interiorul clasei.”

Cod cu generice
class Zoo<T>
{
 ArrayList<T> pets = new ArrayList<T>();

 public T createAnimal()
 {
  T animal = new T();
  pets.add(animal)
  return animal;
 }
}
Ce se întâmplă cu adevărat
class Zoo
{
 ArrayList pets = new ArrayList();

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

„În timpul compilării, toate tipurile de parametri sunt înlocuite cu Object. Și în interiorul clasei nu există informații despre tipul transmis acesteia.”

— Da, sunt de acord, nu e cel mai bun.

"Nu este chiar atât de înfricoșător. Îți voi spune mai târziu cum să ocoliți această problemă."

Dar mai sunt. Java vă permite să specificați un tip părinte pentru parametrii de tip. Cuvântul cheie extins este folosit pentru aceasta. De exemplu:

Cod cu generice
class Zoo<T extends Cat>
{
 T cat;

 T getCat()
 {
  return cat;
 }

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

 String getCatName()
 {
  return this.cat.getName();
 }
}
Ce se întâmplă cu adevărat
class Zoo
{
 Cat cat;

 Cat getCat()
 {
  return cat;
 }

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

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

„Rețineți două fapte:”

„În primul rând, nu poți trece orice tip ca parametru – poți trece doar o pisică sau o clasă care moștenește Cat.”

„În al doilea rând, în interiorul clasei Zoo, variabilele de tip T pot apela acum metodele clasei Cat.  Coloana din dreapta explică de ce (deoarece Cat va fi înlocuită oriunde există un T)”

"Da. Dacă spunem că Cat sau o subclasă a Cat este trecută ca argument de tip, atunci suntem siguri că tipul T va avea întotdeauna metodele clasei Cat."

— Ei bine, asta e inteligent.