This shows you the differences between two versions of the page.
|
poo:breviare:breviar-07 [2025/11/17 20:44] george.tudor1906 |
poo:breviare:breviar-07 [2025/11/19 09:25] (current) george.tudor1906 |
||
|---|---|---|---|
| Line 6: | Line 6: | ||
| == 1.1 Interfața Collection și ierarhia colecțiilor == | == 1.1 Interfața Collection și ierarhia colecțiilor == | ||
| + | |||
| + | {{:poo:breviare:collection.png?600|}} | ||
| O **colecție** este un obiect care grupează mai multe elemente într-o singură unitate. Prin intermediul colecțiilor avem acces la diferite structuri de date: vectori dinamici, liste înlănțuite, stive, mulțimi, tabele de dispersie ș.a.m.d.. Colecțiile sunt folosite atât pentru **memorarea și manipularea datelor**, cât și pentru **transmiterea informațiilor între metode**. | O **colecție** este un obiect care grupează mai multe elemente într-o singură unitate. Prin intermediul colecțiilor avem acces la diferite structuri de date: vectori dinamici, liste înlănțuite, stive, mulțimi, tabele de dispersie ș.a.m.d.. Colecțiile sunt folosite atât pentru **memorarea și manipularea datelor**, cât și pentru **transmiterea informațiilor între metode**. | ||
| Line 267: | Line 269: | ||
| <note important> | <note important> | ||
| Dacă modificați colecția în timpul parcurgerii, folosiți **iterator.remove()** (sau, mai simplu, //removeIf(...)// pe colecție). | Dacă modificați colecția în timpul parcurgerii, folosiți **iterator.remove()** (sau, mai simplu, //removeIf(...)// pe colecție). | ||
| + | </note> | ||
| <code java> | <code java> | ||
| Line 367: | Line 370: | ||
| === 3. Genericitate (generics) === | === 3. Genericitate (generics) === | ||
| - | Fără generics, o colecție **raw** acceptă obiecte de orice fel, iar la citire trebuie să facem conversii (`cast`). Codul devine greu de urmărit, iar amestecul de tipuri poate produce ușor `ClassCastException` la rulare. | + | Fără **generics**, o colecție **raw** acceptă obiecte de orice fel, iar la citire trebuie să facem conversii (//cast//). Codul devine greu de urmărit, iar amestecul de tipuri poate produce ușor //ClassCastException// la rulare. |
| Genericitatea rezolvă exact aceste probleme: | Genericitatea rezolvă exact aceste probleme: | ||
| - | + | * declarăm de la început **tipul elementelor**; | |
| - | * declarăm de la început **tipul elementelor**; | + | * compilatorul verifică și **interzice** inserarea altor tipuri. |
| - | * compilatorul verifică și **interzice** inserarea altor tipuri. | + | |
| <code java> | <code java> | ||
| Line 382: | Line 384: | ||
| int y = list.get(1); // tot fără cast | int y = list.get(1); // tot fără cast | ||
| - | // list.add("Text"); // eroare de compilare: tip incompatibil </code> | + | // list.add("Text"); // eroare de compilare: tip incompatibil |
| + | </code> | ||
| <note warning> | <note warning> | ||
| - | Dacă aveți un caz real în care elementele pot fi de mai multe tipuri, NU reveniți la raw types. | + | Dacă aveți un caz real în care elementele pot fi de mai multe tipuri, **NU** reveniți la raw types. Folosiți: |
| - | Folosiți: | + | * **List<Object>** și verificați cu `instanceof` înainte de cast, |
| - | * `List<Object>` și verificați cu `instanceof` înainte de cast, | + | |
| * sau proiectați o ierarhie comună (o interfață, o clasă părinte) și parametrizați lista cu acest **supertip**. | * sau proiectați o ierarhie comună (o interfață, o clasă părinte) și parametrizați lista cu acest **supertip**. | ||
| - | În toate celelalte situații folosiți colecții parametrizate (`List<Student>`, `Map<String, Integer>`) pentru **siguranță și claritate**. </note> | + | În toate celelalte situații folosiți colecții parametrizate (//List<Student>//, //Map<String, Integer>//) pentru **siguranță și claritate**. </note> |
| - | --- | ||
| === 4. equals() vs hashCode() === | === 4. equals() vs hashCode() === | ||
| - | Metoda `equals(Object)` stabilește **egalitatea logică** dintre două instanțe. Definiția egalității aparține modelului de date (ex.: doi studenți pot fi considerați egali prin CNP, sau prin combinație de câmpuri). | + | Metoda **equals(Object)** stabilește **egalitatea logică** dintre două instanțe. Definiția egalității aparține modelului de date (ex.: doi studenți pot fi considerați egali prin CNP, sau prin combinație de câmpuri). |
| - | Compararea unei instanțe non-null cu referința `null` produce întotdeauna rezultat de inegalitate. Pentru tipuri numerice în virgulă mobilă se recomandă `Double.compare` / `Float.compare`. | + | Metoda **hashCode()** returnează un **rezumat numeric** (int) al obiectului. Colecțiile pe bază de dispersie (//HashSet//, //HashMap//) folosesc acest rezumat pentru localizare rapidă. |
| - | + | ||
| - | Metoda `hashCode()` returnează un **rezumat numeric** (`int`) al obiectului. Colecțiile pe bază de dispersie (`HashSet`, `HashMap`) folosesc acest rezumat pentru localizare rapidă. | + | |
| <note important> | <note important> | ||
| - | * Dacă două obiecte sunt **egale** prin `equals`, atunci **trebuie** să aibă același `hashCode()`. | + | * Dacă două obiecte sunt **egale** prin //equals//, atunci **trebuie** să aibă același //hashCode()//. |
| - | * Inversul nu este obligatoriu (două obiecte diferite pot avea același hashCode). | + | |
| </note> | </note> | ||
| - | În `HashSet` și `HashMap`, operațiile de apartenență și unicitate funcționează astfel: | + | În **HashSet** și **HashMap**, operațiile de apartenență și unicitate funcționează astfel: |
| - | 1. colecția calculează `hashCode()` și alege „bucket-ul”; | + | - colecția calculează **hashCode()** și alege locul elementului; |
| - | 2. confirmă prezența prin `equals()`. | + | - confirmă prezența prin **equals()**. |
| <code java> | <code java> | ||
| Line 417: | Line 415: | ||
| class EqualsHashDemo { | class EqualsHashDemo { | ||
| - | ``` | + | // Varianta corectă: equals și hashCode folosesc ACELEAȘI câmpuri |
| - | // Varianta corectă: equals și hashCode folosesc ACELEAȘI câmpuri | + | static final class GoodStudent { |
| - | static final class GoodStudent { | + | private final String id; |
| - | private final String id; | + | GoodStudent(String id) { this.id = id; } |
| - | GoodStudent(String id) { this.id = id; } | + | |
| - | @Override public boolean equals(Object o) { | + | @Override |
| - | if (this == o) return true; | + | public boolean equals(Object o) { |
| - | if (!(o instanceof GoodStudent g)) return false; | + | if (this == o) return true; |
| - | return Objects.equals(id, g.id); | + | if (!(o instanceof GoodStudent g)) return false; |
| - | } | + | return Objects.equals(id, g.id); |
| + | } | ||
| - | @Override public int hashCode() { | + | @Override |
| - | return Objects.hash(id); | + | public int hashCode() { |
| + | return Objects.hash(id); | ||
| + | } | ||
| } | } | ||
| - | } | ||
| - | // Varianta greșită: equals suprascris, hashCode NU | + | // Varianta greșită: equals suprascris, hashCode NU |
| - | static final class BadStudent { | + | static final class BadStudent { |
| - | private final String id; | + | private final String id; |
| - | BadStudent(String id) { this.id = id; } | + | BadStudent(String id) { this.id = id; } |
| - | @Override public boolean equals(Object o) { | + | @Override |
| - | if (this == o) return true; | + | public boolean equals(Object o) { |
| - | if (!(o instanceof BadStudent b)) return false; | + | if (this == o) return true; |
| - | return Objects.equals(id, b.id); | + | if (!(o instanceof BadStudent b)) return false; |
| + | return Objects.equals(id, b.id); | ||
| + | } | ||
| + | // (fără hashCode) -> folosește Object.hashCode(), diferit pentru instanțe diferite | ||
| } | } | ||
| - | // (fără hashCode) -> folosește Object.hashCode(), diferit pentru instanțe diferite | ||
| - | } | ||
| - | public static void main(String[] args) { | + | public static void main(String[] args) { |
| - | // Caz corect | + | // Caz corect |
| - | GoodStudent a1 = new GoodStudent("42"); | + | GoodStudent a1 = new GoodStudent("42"); |
| - | GoodStudent a2 = new GoodStudent("42"); | + | GoodStudent a2 = new GoodStudent("42"); |
| - | System.out.println("a1.equals(a2) = " + a1.equals(a2)); // true | + | System.out.println("a1.equals(a2) = " + a1.equals(a2)); // true |
| - | System.out.println("a1.hashCode = " + a1.hashCode() | + | System.out.println("a1.hashCode = " + a1.hashCode() |
| - | + " | a2.hashCode = " + a2.hashCode()); // egale | + | + " | a2.hashCode = " + a2.hashCode()); // egale |
| - | Set<GoodStudent> good = new HashSet<>(); | + | Set<GoodStudent> good = new HashSet<>(); |
| - | good.add(a1); | + | good.add(a1); |
| - | good.add(a2); | + | good.add(a2); |
| - | System.out.println("HashSet<GoodStudent>.size = " + good.size()); // 1 | + | System.out.println("HashSet<GoodStudent>.size = " + good.size()); // 1 |
| - | // Caz greșit | + | // Caz greșit |
| - | BadStudent b1 = new BadStudent("42"); | + | BadStudent b1 = new BadStudent("42"); |
| - | BadStudent b2 = new BadStudent("42"); | + | BadStudent b2 = new BadStudent("42"); |
| - | System.out.println("b1.equals(b2) = " + b1.equals(b2)); // true | + | System.out.println("b1.equals(b2) = " + b1.equals(b2)); // true |
| - | System.out.println("b1.hashCode = " + b1.hashCode() | + | System.out.println("b1.hashCode = " + b1.hashCode() |
| - | + " | b2.hashCode = " + b2.hashCode()); // diferite | + | + " | b2.hashCode = " + b2.hashCode()); // diferite |
| - | Set<BadStudent> bad = new HashSet<>(); | + | Set<BadStudent> bad = new HashSet<>(); |
| - | bad.add(b1); | + | bad.add(b1); |
| - | bad.add(b2); | + | bad.add(b2); |
| - | System.out.println("HashSet<BadStudent>.size = " + bad.size()); // 2 (duplicate) | + | System.out.println("HashSet<BadStudent>.size = " + bad.size()); // 2 (duplicate) |
| - | System.out.println("bad.contains(new BadStudent(\"42\")) = " | + | System.out.println("bad.contains(new BadStudent(\"42\")) = " |
| - | + bad.contains(new BadStudent("42"))); // false | + | + bad.contains(new BadStudent("42"))); // false |
| + | } | ||
| } | } | ||
| - | ``` | + | </code> |
| - | + | ||
| - | } </code> | + | |