Differences

This shows you the differences between two versions of the page.

Link to this comparison view

poo-ca-cd:laboratoare:genericitate-si-tipuri-parametrizate [2025/12/08 08:49]
florian_luis.micu [Task 1 (6p)]
poo-ca-cd:laboratoare:genericitate-si-tipuri-parametrizate [2025/12/10 01:06] (current)
florian_luis.micu [Wildcard Capture]
Line 3: Line 3:
   * Autori: [[miculuis1@gmail.com | Florian-Luis Micu ]], [[sorinabuf@gmail.com | Sorina-Anamaria Buf ]], [[stefancocioran@gmail.com | Ștefan Cocioran ]]   * Autori: [[miculuis1@gmail.com | Florian-Luis Micu ]], [[sorinabuf@gmail.com | Sorina-Anamaria Buf ]], [[stefancocioran@gmail.com | Ștefan Cocioran ]]
   * Data publicării:​ 08.12.2025   * Data publicării:​ 08.12.2025
-  * Data ultimei modificări: ​08.12.2025+  * Data ultimei modificări: ​10.12.2025 
 +    * reordonare secțiuni. 
 +    * introducerea Generic Singleton Factory ca materie [Optional]. 
 +    * introducerea CRTP ca materie [Optional].
  
-======Genericics======+======Obiective====== 
 + 
 +Scopul acestui laborator este prezentarea conceptului de genericitate și modalitățile de creare și folosire a claselor, metodelor și interfețelor generice în Java. 
 + 
 +Aspectele urmărite sunt: 
 +  * prezentarea structurilor generice simple. 
 +  * conceptele de wildcard și bounded wildcards. 
 +  * utilitatea genericității în design-ul unui sistem. 
 + 
 +Aspectele **bonus** urmărite sunt: 
 +  * compilarea cu warning-uri pentru raw types și dangerous casts 
 +  * glosar pentru denumirea tipurilor generice. 
 +  * prezentarea pattern-ului avansat Generic Singleton Factory. 
 +  * prezentarea pattern-ului CRTP. 
 + 
 +<note warning>​ 
 +  * În acest laborator există mai multe secțiuni marcate **[Optional]**. Aceste secțiuni cuprind informații **bonus** care vă pot fi prezentate în **timpul laboratorului** sau pe care le puteți aprofunda **în afara** acestuia, ele nefiind necesare pentru laboratoarele viitoare sau pentru teme. 
 +  * De asemenea, veți întâlni câteva secțiuni marcate **[Nice to know]**. Vă recomandăm ca acestea să aibă **prioritate** în parcurgerea secțiunilor de tip **[Optional]**,​ deoarece vă pot oferi informații bonus care să fie și foarte probabil utile pentru **teme** sau **laboratoare viitoare**. 
 +</​note>​ 
 + 
 +======🏷️ Generics======
  
 Genericitatea este unul dintre cele mai elegante mecanisme introduse în Java pentru a ajuta la scrierea unui cod **general**,​ **sigur** și **reutilizabil**. Genericitatea este unul dintre cele mai elegante mecanisme introduse în Java pentru a ajuta la scrierea unui cod **general**,​ **sigur** și **reutilizabil**.
Line 208: Line 231:
  
 Compilatorul deduce **automat** tipul ''​T''​ în fiecare apel. Compilatorul deduce **automat** tipul ''​T''​ în fiecare apel.
 +
 +<note warning>
 +În Java, tipurile generice **nu pot fi primitive**,​ drept urmare va trebui să folosim mereu **obiecte** sau **clase wrapper**.
 +</​note>​
  
 ====Tipuri generice multiple==== ====Tipuri generice multiple====
Line 222: Line 249:
 Aceasta este baza map-urilor, dicționarelor și tuplurilor. Aceasta este baza map-urilor, dicționarelor și tuplurilor.
  
 +====Interfețe generice====
  
-=====Tipuri ​generice ​cu limitări=====+Interfețele pot fi la rândul lor generice:
  
-Există situații în care dorim ca un parametru generic să fie **restricționat** la un anumit tip (sau **subclase** ale acestuia).+<code java> 
 +public interface Transformer<​T,​ R> { 
 +    R apply(T input); 
 +
 +</​code>​ 
 + 
 +<note tip> 
 +Interfața de mai sus este una specială, deoarece se numește ​**interfață funcțională**. Vom discuta mai multe despre acestea în laboratorul viitor. 
 +</​note>​ 
 + 
 +=====Heritable Generics===== 
 + 
 +Generics pot participa ​la **lanțuri de moștenire** exact ca orice alte clase, dar cu câteva detalii importante. 
 + 
 +====Moștenire păstrând parametrul de tip====
  
 <code java> <code java>
-public ​class NumberBox<T extends ​Number> { +class MyList<Textends ​ArrayList<​T> { 
-    ​private T value;+    ​// Moștenește întreaga funcționalitate și rămâne generică
 } }
 </​code>​ </​code>​
  
-Această constrângere oferă două avantaje: +Clasa derivată continuă să fie generică și poate funcționa exact ca tipul original.
-  * garantează că putem apela metodele definite în ''​Number'',​ +
-  * previne utilizarea unor tipuri incompatibile (ex. ''​String''​).+
  
-De asemenea, Java permite **bounded type parameters multiple**:+====Moștenire cu specializarea tipului (fixarea parametrului)====
  
 <code java> <code java>
-public <T extends ​Number & Comparable<T>void process(T value) ​... }+class IntegerList ​extends ​ArrayList<Integer> { }
 </​code>​ </​code>​
  
-Această combinație ​este utilă în **algoritmi de sortare** sau **agregare numerică**.+Clasa nu mai este generică. Acceptă doar valori de tip Integer. 
 + 
 +Acest lucru este util pentru a crea **alias-uri semantice**
 + 
 +<code java> 
 +class UserIdList extends ArrayList<​UserId>​ { } 
 +</​code>​ 
 + 
 +====Moștenire cu parametri ignorați (de evitat)==== 
 + 
 +<code java> 
 +class Bad<​T>​ extends Box<​String>​ { } 
 +</​code>​ 
 + 
 +Parametrul generic T există, dar **nu mai este folosit**. Asta înseamnă că următorul cod compilează:​ 
 + 
 +<code java> 
 +Bad<​Integer>​ b = new Bad<>​();​ 
 +</​code>​ 
 + 
 +Deși clasa funcționează doar cu ''​String''​ intern. Aceasta creează confuzie și design ineficient. 
 + 
 +====Moștenire cu limitări pe tipuri==== 
 + 
 +<code java> 
 +class SortedBox<​T extends Comparable<​T>>​ extends Box<​T>​ { } 
 +</​code>​ 
 + 
 +Clasa poate fi instanțiată doar cu tipuri care sunt comparabile între ele. 
 + 
 +Acest tip de moștenire apare des în structuri de date (liste ordonate, heap-uri, arbori etc.). 
 + 
 +<note tip> 
 +Vom vedea mai jos ce face exact ''​extends''​ în cadrul generics. 
 +</​note>​
  
 =====Wildcards – flexibilitate în genericitate===== =====Wildcards – flexibilitate în genericitate=====
Line 251: Line 325:
 ====Wildcard neîngrădit (?)==== ====Wildcard neîngrădit (?)====
  
-Folosim ? când tipul nu este relevant, ci doar existența lui:+Folosim ​''​?'' ​când tipul nu este relevant, ci doar existența lui:
  
 <code java> <code java>
Line 301: Line 375:
   * **Consumer Super** → folosește ''​super''​ când lista primește valori.   * **Consumer Super** → folosește ''​super''​ când lista primește valori.
 </​note>​ </​note>​
 +
 +<note important>​
 +Deși folosim ''​extends'',​ acesta se poate referi atât la **clase** cât și la **interfețe** (vezi exemplul de mai sus despre Comparable).
 +</​note>​
 +
 +====Wildcard Capture====
 +
 +Wildcard-urile (''?''​) sunt utile pentru flexibilitate,​ dar **nu** pot fi folosite ca **tipuri reale** în operații care necesită consistență de tip.
 +
 +De exemplu, următoarea metodă nu compilează:​
 +
 +<code java>
 +void resetFirst(List<?>​ list) {
 +    list.set(0, list.get(0));​ // Eroare
 +}
 +</​code>​
 +
 +Motivul:
 +  * ''​list.get(0)''​ întoarce un ''​Object''​
 +  * ''​list.set''​ necesită un tip exact, pe care ''?''​ nu îl reprezintă
 +  * compilatorul nu poate garanta că tipurile sunt compatibile
 +
 +Wildcard-ul înseamnă “nu cunosc tipul”, deci nu poate fi folosit ca tip concret.
 +
 +Pentru a rezolva această problemă, folosim **Wildcard Capture**. Definim o **metodă generică auxiliară** care introduce un **parametru de tip real**:
 +
 +<code java>
 +<T> void resetHelper(List<​T>​ list) {
 +    list.set(0, list.get(0));​ // Aici merge
 +}
 +
 +void resetFirst(List<?>​ list) {
 +    resetHelper(list);​ // Compilatorul captează wildcard-ul ca tip T
 +}
 +</​code>​
 +
 +**Ce se întâmplă aici?**
 +  * ''<?>''​ este “capturat” și tratat ca un tip ''​T''​ concret
 +  * compilatorul poate garanta coerența între ''​get()''​ și ''​set()''​
 +  * funcția helper permite operații care altfel ar fi imposibile
 +
 +===Un exemplu clasic din JDK===
 +
 +Metoda ''​Collections.swap''​ folosește exact acest mecanism:
 +
 +<code java>
 +static void swap(List<?>​ list, int i, int j) {
 +    swapHelper(list,​ i, j);
 +}
 +
 +private static <T> void swapHelper(List<​T>​ list, int i, int j) {
 +    T tmp = list.get(i);​
 +    list.set(i, list.get(j));​
 +    list.set(j, tmp);
 +}
 +</​code>​
 +
 +  - Metoda publică primește orice listă (''​List<?>''​).
 +  - Metoda privată capturează wildcard-ul ca ''​T''​ și permite operații sigure.
 +
 +=====Tipuri generice cu limitări=====
 +
 +Există situații în care dorim ca un parametru generic să fie **restricționat** la un anumit tip (sau **subclase** ale acestuia). ​
 +
 +Pentru a limita un tip putem folosi keyword-ul ''​extends'',​ astfel doar o clasă moștenită de clasa extinsă poate fi folosită. În acest caz, această noțiune se cheamă **bounded generics**.
 +
 +<code java>
 +public class NumberBox<​T extends Number> {
 +    private T value;
 +}
 +</​code>​
 +
 +Această constrângere oferă două avantaje:
 +  * garantează că putem apela metodele definite în ''​Number'',​
 +  * previne utilizarea unor tipuri incompatibile:​
 +    * ''​NumberBox<​Integer>''​ - valid
 +    * ''​NumberBox<​Double>''​ - valid
 +    * ''​NumberBox<​String>''​ - invalid
 +
 +====Limitări multiple====
 +
 +De asemenea, Java permite **multiple bounded type parameters**:​
 +
 +<code java>
 +public <T extends Number & Comparable<​T>>​ void process(T value) { ... }
 +</​code>​
 +
 +Ordinea este importantă:​
 +  - prima limitare trebuie să fie o clasă
 +  - restul pot fi interfețe
 +
 +Combinația de mai sus este utilă în **algoritmi de sortare** sau **agregare numerică**.
 +
 +Un alt exemplu destul de des folosit cu limitări în tipuri generice este acesta:
 +
 +<code java>
 +public static <T extends Comparable<​T>>​ T max(T a, T b) {
 +    return a.compareTo(b) > 0 ? a : b;
 +}
 +</​code>​
 +
 +Practic, am făcut o metodă care întoarce maximul dintre două obiecte, doar dacă acel obiect **implementează interfața Comparable** pentru a putea folosi metoda ''​compareTo''​.
 +
 +
 +
  
 =====Type erasure – cum funcționează generics sub capotă===== =====Type erasure – cum funcționează generics sub capotă=====
Line 319: Line 498:
   - Tipurile sunt transformate în Object sau limitele lor (extends).   - Tipurile sunt transformate în Object sau limitele lor (extends).
  
 +<spoiler [Nice to know] Instanțierea unui tip generic>
 +
 +Nu putem scrie ''​new T()'',​ deoarece tipul T **nu există la runtime** și Java nu știe dacă acest tip are un constructor fără parametrii. Drept consecință,​ codul următor este invalid:
 +
 +<code java>
 +public class Box<​T>​ {
 +   ​private T value = new T(); // EROARE
 +}
 +</​code>​
 +
 +Dar, putem folosi următorul exemplu de cod pentru a construi obiecte generice:
 +
 +<code java>
 +public class Box<​T>​ {
 +   ​private final T value;
 +
 +   ​public Box(Class<​T>​ clazz) throws Exception {
 +       ​this.value = clazz.getDeclaredConstructor().newInstance();​
 +   }
 +}
 +</​code>​
 +
 +</​spoiler>​
 +
 +<​html><​br></​html>​
 ====Bridge Methods==== ====Bridge Methods====
  
Line 362: Line 566:
 =====Invarianță,​ Covarianță și Contravarianță===== =====Invarianță,​ Covarianță și Contravarianță=====
  
-Java are trei moduri principale de a trata relațiile dintre tipurile generice.+Java are **trei moduri principale** de a trata relațiile dintre tipurile generice.
  
 ====Invarianță (comportamentul implicit)==== ====Invarianță (comportamentul implicit)====
Line 392: Line 596:
 ====Contravarianță (? super T)==== ====Contravarianță (? super T)====
  
-Pentru a defini un scenariu de moștenire ca în exemplul despre invarianță,​ putem folosi bounded wildcards, astfel listelor li se poate permite să accepte **tipuri părinte**.+Pentru a defini un scenariu de moștenire ca în exemplul despre invarianță,​ putem folosi ​**bounded wildcards**, astfel listelor li se poate permite să accepte **tipuri părinte**.
  
 <code java> <code java>
Line 399: Line 603:
  
 Aceasta permite scrierea în colecție (''​add(Integer)''​),​ dar **nu permite** citirea unui tip specific. Aceasta permite scrierea în colecție (''​add(Integer)''​),​ dar **nu permite** citirea unui tip specific.
 +
 +====De ce List<​String>​ nu este List<​Object>?​====
 +
 +În mod natural, ai putea crede că dacă ''​String''​ este un subtip al lui ''​Object'',​ atunci și ''​List<​String>''​ ar trebui să fie un subtip al lui ''​List<​Object>''​. Dar nu este așa.
 +
 +Exemplu:
 +<code java>
 +List<​String>​ stringList = new ArrayList<>​();​
 +
 +// Deși pare logic, nu este permis:
 +List<​Object>​ objects = stringList; ​  // Eroare de compilare!
 +</​code>​
 +
 +De ce? Dacă ar fi fost permis, atunci:
 +<code java>
 +objects.add(new Object()); ​  // ar fi permis...
 +String s = stringList.get(0);​ // ...dar aici am obține un Object, nu un String!
 +</​code>​
 +
 +Acesta este motivul pentru care generics în Java sunt invariante.
  
 =====Cast-uri în Generics===== =====Cast-uri în Generics=====
Line 432: Line 656:
  
 <note tip> <note tip>
-Arrays verifică tipurile la runtime, în schimb generics nu o fac.+  * **Reified** înseamnă că informația despre **tip** există și este păstrată la **runtime**. 
 +  * Arrays verifică tipurile la **runtime**, în schimb generics nu o fac.
 </​note>​ </​note>​
 +
 +=====[Nice to know] Glosar – Litere folosite în Generics=====
 +
 +^Literă ^ Semnificație^
 +|T | Type|
 +|E | Element (în special în colecții)|
 +|K | Key|
 +|V | Value|
 +|R | Result|
 +|? | wildcard, tip necunoscut|
 +
  
 =====[Optional] Warning-uri de compilare===== =====[Optional] Warning-uri de compilare=====
Line 448: Line 684:
 IntelliJ va rula automat această comandă pentru voi. IntelliJ va rula automat această comandă pentru voi.
 </​note>​ </​note>​
-=====[Nice to know] Glosar – Litere folosite în Generics===== 
  
-^Literă ^ Semnificație^ +=====[Optional] Generic Singleton Factory===== 
-|| Type| + 
-|E | Element ​(în special în colecții)| +Acesta este un pattern foarte elegant, folosit intern în **JDK**, mai ales în ''​Collections''​. 
-|K | Key| + 
-|V | Value| +O singură instanță poate fi folosită pentru **toate tipurile**, iar generics asigură siguranța. 
-|R | Result| + 
-|| wildcard, ​tip necunoscut|+<code java> 
 +public class SingletonFactory { 
 +    private static final Box<​Object>​ INSTANCE = new Box<>​();​ 
 + 
 +    @SuppressWarnings("​unchecked"​) 
 +    ​public static <T> Box<​T>​ getInstance() { 
 +        ​return ​(Box<​T>​) INSTANCE; 
 +    } 
 +
 +</​code>​ 
 + 
 +Utilizare:​ 
 + 
 +<code java> 
 +Box<​String>​ a = SingletonFactory.getInstance();​ 
 +Box<​Integer>​ b = SingletonFactory.getInstance();​ 
 +</​code>​ 
 + 
 + 
 +Observație: 
 +  * Instanța din spate e aceeași (''​Box<​Object>''​). 
 +  * Dar fiecare apelant primește o versiune tipizată în siguranță. 
 + 
 +<note important>​ 
 +De ce funcționează codul de mai sus? 
 +  - instanța este imutabilă sau fără stare 
 +  - cast-ul este sigur 
 +  - comportamentul este identic pentru orice tip 
 +</​note>​ 
 + 
 +<note tip> 
 +Acest pattern apare în: 
 +  * ''​Collections.emptyList()''​ 
 +  * ''​Collections.emptyMap()''​ 
 +  * ''​Optional.empty()''​ 
 +  * ''​Stream.empty()''​ 
 +</​note>​ 
 + 
 +=====[Optional] Self-bounded Generics (Curiously Recurring Template Pattern — CRTP)===== 
 + 
 +Este un pattern avansat unde un **tip generic** se referă la el **însuși**. 
 + 
 +<code java> 
 +class ComparableSelf<​T extends ComparableSelf<​T>>​ { } 
 +</​code>​ 
 + 
 +Scopul acestui pattern este de a asigura că **subclasele** folosesc un **tip compatibil cu ele însele**. 
 + 
 +De exemplu: 
 +<code java> 
 +class Person extends ComparableSelf<​Person>​ { } 
 +</​code>​ 
 + 
 +Beneficiul major este că putem scrie algoritmi care impun **tipuri consistente**. 
 + 
 +Exemplu tipic: 
 +<code java> 
 +interface SelfComparable<​T extends SelfComparable<​T>>​ { 
 +    int compareTo(T other); 
 +
 +</​code>​ 
 + 
 +Implementare corectă: 
 +<code java> 
 +class Car implements SelfComparable<​Car>​ { 
 +    public int compareTo(Car other) { ... } 
 +
 +</​code>​ 
 + 
 +Implementare incorectă (interzisă de self-bounding):​ 
 +<code java> 
 +class Car implements SelfComparable<​Object>​ { ... } 
 +</​code>​ 
 + 
 +Self-bounded generics **împiedică** astfel de erori de design. 
 + 
 ======Exerciții====== ======Exerciții======
  
Line 487: Line 798:
  
  
 +====== Resurse și link-uri utile ======
  
 +  * [[https://​www.baeldung.com/​java-generics|The Basics of Java Generics - Baeldung]]
 +  * [[https://​www.c-sharpcorner.com/​article/​how-c-sharp-generics-stand-out-a-comparison/​|How C# Generics is different from Java Generics - C# Corner]]
  
  
poo-ca-cd/laboratoare/genericitate-si-tipuri-parametrizate.1765176556.txt.gz · Last modified: 2025/12/08 08:49 by florian_luis.micu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0