This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
laboratoare:genericitate [2016/11/19 23:16] Cosmin Petrisor [Type Erasure] |
laboratoare:genericitate [2019/11/24 19:44] (current) Florin Mihalache [Exerciții] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| = Genericitate = | = Genericitate = | ||
| - | * Responsabil: [[cosmin_ioan.petrisor@cti.pub.ro|Cosmin Petrişor]] | + | == Obiective == |
| - | * Data publicării: 19.11.2016 | + | |
| - | * Data ultimei modificări: 19.11.2016 | + | |
| - | == Introducere == | + | Scopul acestui laborator este prezentarea conceptului de genericitate și modalitățile de creare și folosire a claselor, metodelor și interfețelor generice în Java. |
| - | Genericitatea este un concept nou, introdus o dată cu JDK 5.0. Din unele puncte de vedere se poate asemăna cu conceptul de //template// din C++. Mecanismul genericității oferă un mijloc de **abstractizare a tipurilor de date** și este util mai ales în ierarhia de colecții. | + | Aspectele urmărite sunt: |
| + | * prezentarea structurilor generice simple | ||
| + | * conceptele de wildcard și bounded wildcards | ||
| + | * utilitatea genericității în design-ul unui sistem | ||
| + | |||
| + | |||
| + | == Introducere == | ||
| Să urmărim exemplul de mai jos: | Să urmărim exemplul de mai jos: | ||
| Line 42: | Line 46: | ||
| void add(E x); | void add(E x); | ||
| Iterator<E> iterator(); | Iterator<E> iterator(); | ||
| - | ... | ||
| } | } | ||
| Line 52: | Line 55: | ||
| </code> | </code> | ||
| - | Sintaxa ''<E>'' este folosită pentru a defini tipuri formale în cadrul interfețelor. Aceste tipuri pot fi folosite în mod asemănător cu tipurile uzuale, cu anumite restricții totuși. În momentul în care invocăm o structură generică ele vor fi înlocuite cu tipurile efective utilizate în invocare. Concret, fie un apel de forma: | + | Sintaxa ''<E>'' (poate fi folosită orice literă) este folosită pentru a defini tipuri formale în cadrul interfețelor. Aceste tipuri pot fi folosite în mod asemănător cu tipurile uzuale, cu anumite restricții totuși. În momentul în care invocăm o structură generică ele vor fi înlocuite cu tipurile efective utilizate în invocare. Concret, fie un apel de forma: |
| <code java> | <code java> | ||
| Line 60: | Line 63: | ||
| În această situație, tipul formal ''E'' a fost înlocuit (la compilare) cu tipul efectiv ''Integer''. | În această situație, tipul formal ''E'' a fost înlocuit (la compilare) cu tipul efectiv ''Integer''. | ||
| - | |||
| - | <note> | ||
| - | O analogie (simplistă) referitoare la acest mecanism de lucru cu tipurile se poate face cu mecanismul funcțiilor: acestea se definesc utilizând parametri //formali//, urmând ca în momentul unui apel acești parametri să fie înlocuiți cu parametri //actuali//. | ||
| - | </note> | ||
| == Genericitatea în subtipuri == | == Genericitatea în subtipuri == | ||
| Line 174: | Line 173: | ||
| <note> | <note> | ||
| - | Trebuie reținut faptul că **în continuare nu putem introduce valori** într-o colecție ce folosește //bounded wildcards// și este dată ca parametru unei funcții. | + | Utilizarea bounded wildcards se manifestă în următoarele 2 situații : |
| + | * lower bounded wildcards se folosesc atunci când vrem să **modificăm** o colecție generică | ||
| + | * upper bounded wildcards se folosesc atunci când vrem să **parcurgem fără să modificăm** o colecție generică | ||
| </note> | </note> | ||
| Line 232: | Line 233: | ||
| == Metode generice == | == Metode generice == | ||
| - | Java ne oferă posibilitatea scrierii de metode generice (deci având un tip-parametru) pentru a facilita prelucrarea unor structuri generice (date ca parametru). | + | Java ne oferă posibilitatea scrierii de metode generice (deci având un tip-parametru) pentru a facilita prelucrarea unor structuri generice. |
| Să exemplificăm acest fapt. Observăm în continuare 2 căi de implementare ale unei metode ce copiază elementele unui vector intrinsec într-o colecție: | Să exemplificăm acest fapt. Observăm în continuare 2 căi de implementare ale unei metode ce copiază elementele unui vector intrinsec într-o colecție: | ||
| <code java> | <code java> | ||
| - | // Metoda corecta | + | // Metoda corectă |
| static <T> void correctCopy(T[] a, Collection<T> c) { | static <T> void correctCopy(T[] a, Collection<T> c) { | ||
| for (T o : a) | for (T o : a) | ||
| - | c.add(o); // Operatia va fi permisa | + | c.add(o); // Operaţia va fi permisă |
| } | } | ||
| - | // Metoda incorecta | + | // Metoda incorectă |
| static void incorrectCopy(Object[] a, Collection<?> c) { | static void incorrectCopy(Object[] a, Collection<?> c) { | ||
| for (Object o : a) | for (Object o : a) | ||
| - | c.add(o); // Operatie incorecta, semnalata ca eroare de catre compilator | + | c.add(o); // Operatie incorectă, semnalată ca eroare de către compilator |
| } | } | ||
| </code> | </code> | ||
| - | Trebuie remarcat faptul că //correctCopy()// este o metodă validă, care se execută corect, însă //incorrectCopy()// nu este, din cauza limitării pe care o cunoaştem deja, referitoare la adăugarea elementelor într-o colecție generică cu tip specificat. Putem remarca, de asemenea, că, și în acest caz, putem folosi //wildcards// sau //bounded wildcards//. Astfel, următoarele declaraţii de metode sunt corecte: | + | Trebuie remarcat faptul că ''correctCopy()'' este o metodă validă, care se execută corect, însă ''incorrectCopy()'' nu este, din cauza limitării pe care o cunoaştem deja, referitoare la adăugarea elementelor într-o colecție generică cu tip specificat. Putem remarca, de asemenea, că, și în acest caz, putem folosi //wildcards// sau //bounded wildcards//. Astfel, următoarele declaraţii de metode sunt corecte: |
| <code java> | <code java> | ||
| - | // O metoda ce copiaza elementele dintr-o lista in alta lista | + | // Copiază elementele dintr-o listă în altă listă |
| public static <T> void copy(List<T> dest, List<? extends T> src) { ... } | public static <T> void copy(List<T> dest, List<? extends T> src) { ... } | ||
| - | // O metoda de adaugare a unor elemente intr-o colectie, cu restrictionarea tipului generic | + | // Adaugă elemente dintr-o colecţie în alta, cu restricţionarea tipului generic |
| public <T extends E> boolean addAll(Collection<T> c); | public <T extends E> boolean addAll(Collection<T> c); | ||
| </code> | </code> | ||
| Line 261: | Line 262: | ||
| == Exerciții == | == Exerciții == | ||
| - | - (**6p**) Implementați o **coadă de priorități** care acceptă doar //tipuri comparabile// (descendente din ''java.lang.Comparable''). Folosiți coada pentru a **sorta în ordine crescătoare** o serie de valori (veți testa valori numerice, generate aleator). Utilizați //bounded wildcards//. | + | - (**6p**) Implementați o **tabelă de dispersie** generică care va permite să stocaţi perechi de tip cheie-valoare. |
| - | * (**1p**) Aveți grijă la tipul parametrului cozii pe care o implementați (este restricționat) | + | * (**2p**) Scrieţi antetul clasei ''MyHashMap'' şi prototipul funcţiilor **put** şi **get**. Aveţi grijă la parametrizarea tipurilor. |
| - | * (**3p**) Pentru păstrarea la orice moment a ordinii valorilor conținute în colecția voastră, puteți să implementați coada ca o listă simplu-înlănțuită, în care capul listei să fie cel mai "mic" element | + | * (**2p**) Implementaţi metoda **put**. Vă puteți crea o clasă internă cu rol de //entry// şi puteţi stoca //entry-urile// într-o colecţie generică existentă în Java. |
| - | * Vă puteți crea o clasă internă care să încapsuleze un nod de listă înlănțuită | + | * (**1p**) Implementaţi metoda **get**. |
| - | * Atenție la adăugarea de noduri în coadă și la cazurile extreme | + | * (**1p**) Testaţi implementarea voastră folosind o clasă definită de voi, care suprascrie metoda **hashCode** din ''Object''. |
| - | * (**1p**) Folosiți o **colecție generică** în care veți stoca valorile numerice inițiale (de adăugat) | + | |
| - | * (**1p**) Implementați **o metodă generică** de copiere a valorilor din această colecție în coada de priorități. | + | |
| - | * (**Bonus 3p**) Implementați colecția voastră ca //iterabilă//, compatibilă cu syntactic-sugar-ul **for-each** | + | |
| - | * Trebuie să implementați interfața ''Iterable''; atenție, și ea este generică | + | |
| - | * Creați-vă //iteratorul// (parametrizat!) ca o clasă internă care să rețină datele necesare (nodul din listă la care a ajuns, etc.) | + | |
| - | * nu este necesar să implementați metoda ''remove'' din ''Iterator'' | + | |
| - | * Afișați-vă acum rezultatele folosind **for-each** pe coada voastră! | + | |
| - (**4p**) Să considerăm interfața ''Sumabil'', ce conține metoda ''void addValue(Sumabil value)''. Această metodă adună la valoarea curentă (stocată în instanța ce apelează metoda) o altă valoare, aflată într-o instanță cu același tip. Pornind de la această interfață, va trebui să: | - (**4p**) Să considerăm interfața ''Sumabil'', ce conține metoda ''void addValue(Sumabil value)''. Această metodă adună la valoarea curentă (stocată în instanța ce apelează metoda) o altă valoare, aflată într-o instanță cu același tip. Pornind de la această interfață, va trebui să: | ||
| * Definiți clasele ''MyVector3'' și ''MyMatrix'' (ce reprezintă un vector cu 3 coordonate și o matrice de dimensiune 4 x 4), ce implementează Sumabil | * Definiți clasele ''MyVector3'' și ''MyMatrix'' (ce reprezintă un vector cu 3 coordonate și o matrice de dimensiune 4 x 4), ce implementează Sumabil | ||
| Line 279: | Line 273: | ||
| == Resurse == | == Resurse == | ||
| * <html><a class="media mediafile mf_pdf" href="/poo/laboratoare/genericitate?do=export_pdf">PDF laborator</a></html> | * <html><a class="media mediafile mf_pdf" href="/poo/laboratoare/genericitate?do=export_pdf">PDF laborator</a></html> | ||
| - | * {{|Soluții}} | ||
| ==Referinţe== | ==Referinţe== | ||