User Tools

Site Tools


Problem constructing authldap
laboratoare:genericitate
Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:genericitate [2016/11/19 23:13]
Cosmin Petrisor [Bounded Wildcards]
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>​
  
 == Type Erasure == == Type Erasure ==
  
-[[https://​docs.oracle.com/​javase/​tutorial/​java/​generics/​erasure.html | Type Erasure]] este un mecanism prin care compilatorul Java înlocuieşte la **compile time** parametrii de genericitate ai unei clase generice cu prima lor apariţie (ţinând cont de restricţii în cazul Bounded Wildcards) sau cu ''​Object''​ dacǎ parametrii nu apar (Raw Type). De exemplu, următorul cod:+[[https://​docs.oracle.com/​javase/​tutorial/​java/​generics/​erasure.html|Type Erasure]] este un mecanism prin care compilatorul Java înlocuieşte la **compile time** parametrii de genericitate ai unei clase generice cu prima lor apariţie (ţinând cont de restricţii în cazul Bounded Wildcards) sau cu ''​Object''​ dacǎ parametrii nu apar (Raw Type). De exemplu, următorul cod:
  
 <code java> <code java>
Line 198: Line 199:
  
 <code java> <code java>
-class  GenericClass <T>{+class  GenericClass <T> {
     void genericFunction(List<​String>​ stringList) {     void genericFunction(List<​String>​ stringList) {
         stringList.add("​foo"​);​         stringList.add("​foo"​);​
     }     }
     // {...}     // {...}
-   public static void main(String[] args) { +    ​public static void main(String[] args) { 
-       ​GenericClass genericClass = new GenericClass();​ +        GenericClass genericClass = new GenericClass();​ 
-       ​List<​Integer>​ integerList = new ArrayList<​Integer>​();​ +        List<​Integer>​ integerList = new ArrayList<​Integer>​();​ 
-       ​integerList.add(100);​ + 
-       ​genericClass.genericFunction(integerList);​ +        ​integerList.add(100);​ 
-       ​System.out.println(integerList.get(0));​ // 100 +        genericClass.genericFunction(integerList);​ 
-       ​System.out.println(integerList.get(1));​ // foo + 
-   ​}+        ​System.out.println(integerList.get(0));​ // 100 
 +        System.out.println(integerList.get(1));​ // foo 
 +    }
 } }
 </​code>​ </​code>​
  
-Observăm că în ''​main''​ se instanţiază clasa ''​GenericClass''​ cu Raw Type, apoi se trimite ca argument metodei ''​genericFunction''​ un ''​ArrayList<​Integer>''​. Codul nu va genera erori şi va afişa //100//, apoi //foo//. Acest lucru se întâmplă tot din cauza mecanismului de Type Erasure. Să urmărim ce se întâmplă:​ la instanţierea clasei ''​GenericClass''​ nu se specifică tipul generic al acesteia iar compilatorul va înlocui în corpul clasei peste tot //T// cu ''​Object''​ şi va dezactiva verificarea de tip. Așadar, obiectul ''​genericClass''​ va aparţine unei clase de forma:+Observăm că în ''​main''​ se instanţiază clasa ''​GenericClass''​ cu Raw Type, apoi se trimite ca argument metodei ''​genericFunction''​ un ''​ArrayList<​Integer>''​. Codul nu va genera erori şi va afişa //100//, apoi //foo//. Acest lucru se întâmplă tot din cauza mecanismului de **Type Erasure**. Să urmărim ce se întâmplă:​ la instanţierea clasei ''​GenericClass''​ nu se specifică tipul generic al acesteia iar compilatorul va înlocui în corpul clasei peste tot ''​T'' ​cu ''​Object''​ şi va dezactiva verificarea de tip. Așadar, obiectul ''​genericClass''​ va aparţine unei clase de forma:
  
 <code java> <code java>
Line 226: Line 229:
 </​code>​ </​code>​
 <note important>​ <note important>​
-Modelul de mai sus este bad practice tocmai pentru că are un comportament nedeterminat și poate conduce la erori. De aceea nu e recomandat să folosiți Raw Types, ci să specificați **întotdeauna** tipul obiectelor în cazul instanțierii claselor generice!+Modelul de mai sus este **bad practice** tocmai pentru că are un comportament nedeterminat și poate conduce la erori. De aceea nu e recomandat să folosiți Raw Types, ci să specificați **întotdeauna** tipul obiectelor în cazul instanțierii claselor generice!
 </​note>​ </​note>​
 == 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 ​incorectasemnalata ​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 259: 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țcoada pentru a **sorta în ordine crescătoare** o serie de valori (veț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'' ​ş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țsă implementați coada ca o listă simplu-înlănțuită,​ în care capul listei să fie cel mai "​mic"​ element +    * (**2p**) Implementaţmetoda **put**. Vă puteți crea o clasă internă ​cu rol de //entry// şputeţ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ţmetoda ​**get**. 
-      * Atenție la adăugarea de noduri în coadă șla cazurile extreme +    * (**1p**) Testaţimplementarea ​voastră ​folosind o clasă definită de voicare 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ț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 277: 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==
  
laboratoare/genericitate.1479590034.txt.gz · Last modified: 2016/11/19 23:13 by Cosmin Petrisor