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 09:18]
florian_luis.micu [Type erasure – cum funcționează generics sub capotă]
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].
  
 ======Obiective====== ======Obiective======
Line 17: Line 20:
   * compilarea cu warning-uri pentru raw types și dangerous casts   * compilarea cu warning-uri pentru raw types și dangerous casts
   * glosar pentru denumirea tipurilor generice.   * glosar pentru denumirea tipurilor generice.
 +  * prezentarea pattern-ului avansat Generic Singleton Factory.
 +  * prezentarea pattern-ului CRTP.
  
 <note warning> <note warning>
Line 23: Line 28:
 </​note>​ </​note>​
  
-======🏷️ ​Genericics======+======🏷️ ​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 257: Line 262:
 Interfața de mai sus este una specială, deoarece se numește **interfață funcțională**. Vom discuta mai multe despre acestea în laboratorul viitor. 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>​ </​note>​
-=====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).+=====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''​).+
  
-<note tip> +====Moștenire cu specializarea tipului (fixarea parametrului)====
-Vom vedea mai jos ce presupune exact construcția ''​extends''​ în cadrul generics. +
-</​note>​+
  
-De asemenea, Java permite ​**bounded type parameters multiple**:+<code java> 
 +class IntegerList extends ArrayList<​Integer>​ { } 
 +</​code>​ 
 + 
 +Clasa nu mai este generică. Acceptă doar valori de tip Integer. 
 + 
 +Acest lucru este util pentru a crea **alias-uri semantice**:
  
 <code java> <code java>
-public <T extends ​Number & Comparable<T>void process(T value) ​... }+class UserIdList ​extends ​ArrayList<UserId> { }
 </​code>​ </​code>​
  
-Această combinație este utilă în **algoritmi ​de sortare** sau **agregare numerică**.+====Moștenire cu parametri ignorați (de evitat)====
  
-Un alt exemplu destul de des folosit cu limitări în tipuri generice ​este acesta:+<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> <code java>
-public static ​<T extends Comparable<T>> T max(T a, T b+Bad<Integer> b = new Bad<>();
-    return a.compareTo(b) > 0 ? a : b; +
-}+
 </​code>​ </​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''​.+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 301: 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 355: Line 379:
 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). 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>​ </​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''​.
 +
 +
  
  
Line 442: 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 472: 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 479: 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 512: 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 528: 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======
  
poo-ca-cd/laboratoare/genericitate-si-tipuri-parametrizate.1765178283.txt.gz · Last modified: 2025/12/08 09:18 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