This shows you the differences between two versions of the page.
poo-ca-cd:laboratoare:genericitate [2020/07/28 23:08] 127.0.0.1 external edit |
poo-ca-cd:laboratoare:genericitate [2023/12/17 19:13] (current) florin.subtirica [Exerciții] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | = Genericitate = | + | ===== Laboratorul 10: Genericitate ===== |
- | == Obiective == | + | ==== Obiective ==== |
Line 7: | Line 7: | ||
Aspectele urmărite sunt: | Aspectele urmărite sunt: | ||
- | * prezentarea structurilor generice simple | + | * prezentarea structurilor generice simple |
- | * conceptele de wildcard și bounded wildcards | + | * conceptele de wildcard și bounded wildcards |
- | * utilitatea genericității în design-ul unui sistem | + | * utilitatea genericității în design-ul unui sistem |
- | == Introducere == | + | ==== Introducere ==== |
Să urmărim exemplul de mai jos: | Să urmărim exemplul de mai jos: | ||
Line 38: | Line 38: | ||
* creșterea gradului de robusteţe | * creșterea gradului de robusteţe | ||
- | == Definirea unor structuri generice simple == | + | ==== Definirea unor structuri generice simple ==== |
Să urmărim câteva elemente din definiția oferită de Java pentru tipurile ''List'' și ''Iterator''. | Să urmărim câteva elemente din definiția oferită de Java pentru tipurile ''List'' și ''Iterator''. | ||
Line 64: | Line 64: | ||
Î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''. | ||
- | == Genericitatea în subtipuri == | + | ==== Genericitatea în subtipuri ==== |
Să considerăm următoarea situaţie: | Să considerăm următoarea situaţie: | ||
Line 84: | Line 84: | ||
Dacă //ChildType// este un subtip (clasă descendentă sau subinterfață) al lui //ParentType//, atunci o structură generică //GenericStructure<ChildType>// **nu** este un subtip al lui //GenericStructure<ParentType>//. **Atenție** la acest concept, întrucât el nu este intuitiv! | Dacă //ChildType// este un subtip (clasă descendentă sau subinterfață) al lui //ParentType//, atunci o structură generică //GenericStructure<ChildType>// **nu** este un subtip al lui //GenericStructure<ParentType>//. **Atenție** la acest concept, întrucât el nu este intuitiv! | ||
</note> | </note> | ||
- | == Wildcards == | + | ==== Wildcards ==== |
//Wildcard//-urile sunt utilizate atunci când dorim să întrebuințăm o structură generică drept //parametru// într-o funcție și nu dorim să limităm tipul de date din colecția respectivă. | //Wildcard//-urile sunt utilizate atunci când dorim să întrebuințăm o structură generică drept //parametru// într-o funcție și nu dorim să limităm tipul de date din colecția respectivă. | ||
Line 104: | Line 104: | ||
</code> | </code> | ||
- | O limitare care intervine însă este că **nu putem adǎuga elemente arbitrare** într-o colecție cu //wildcard//-uri: | + | O limitare care intervine însă este că **nu putem adăuga elemente arbitrare** într-o colecție cu //wildcard//-uri: |
<code java> | <code java> | ||
Line 123: | Line 123: | ||
</code> | </code> | ||
- | == Bounded Wildcards == | + | ==== Bounded Wildcards ==== |
În anumite situații, faptul că un //wildcard// poate fi înlocuit cu orice tip se poate dovedi un inconvenient. Mecanismul bazat pe **Bounded Wildcards** permite introducerea unor restricţii asupra tipurilor ce pot înlocui un //wildcard//, obligându-le să se afle într-o relație ierarhică (de descendență) față de un tip fix specificat. | În anumite situații, faptul că un //wildcard// poate fi înlocuit cu orice tip se poate dovedi un inconvenient. Mecanismul bazat pe **Bounded Wildcards** permite introducerea unor restricţii asupra tipurilor ce pot înlocui un //wildcard//, obligându-le să se afle într-o relație ierarhică (de descendență) față de un tip fix specificat. | ||
Line 170: | Line 170: | ||
</code> | </code> | ||
- | Sintaxa ''List<? extends Pizza>'' ([[:poo-ca-cd:https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html|Upper Bounded Wildcards]]) impune ca tipul elementelor listei să fie ''Pizza'' sau o subclasă a acesteia. Astfel, ''pList'' ar fi putut avea, la fel de bine, tipul ''List<HamPizza>'' sau ''List<CheesePizza>''. În mod similar, putem imprima constrângerea ca tipul elementelor listei să fie ''Pizza'' sau o superclasă a acesteia, utilizând sintaxa ''List<? super Pizza>'' ([[:poo-ca-cd:https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html|Lower Bounded Wildcards]]). | + | Sintaxa ''List<? extends Pizza>'' ([[https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html|Upper Bounded Wildcards]]) impune ca tipul elementelor listei să fie ''Pizza'' sau o subclasă a acesteia. Astfel, ''pList'' ar fi putut avea, la fel de bine, tipul ''List<HamPizza>'' sau ''List<CheesePizza>''. În mod similar, putem imprima constrângerea ca tipul elementelor listei să fie ''Pizza'' sau o superclasă a acesteia, utilizând sintaxa ''List<? super Pizza>'' ([[https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html|Lower Bounded Wildcards]]). |
<note> | <note> | ||
Utilizarea bounded wildcards se manifestă în următoarele 2 situaț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ă | + | * 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ă | + | * 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 ==== |
- | [[:poo-ca-cd: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 188: | Line 188: | ||
</code> | </code> | ||
- | se va transforma dupǎ acest pas al compilării în: | + | se va transforma după acest pas al compilării în: |
<code java> | <code java> | ||
Line 196: | Line 196: | ||
</code> | </code> | ||
- | Sǎ urmǎrim urmǎtorul fragment de cod: | + | Să urmărim următorul fragment de cod: |
<code java> | <code java> | ||
Line 231: | Line 231: | ||
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. | Java ne oferă posibilitatea scrierii de metode generice (deci având un tip-parametru) pentru a facilita prelucrarea unor structuri generice. | ||
Line 260: | Line 260: | ||
</code> | </code> | ||
- | == Exerciții == | + | ==== Exemple genericitate ==== |
+ | Probabil nu sunteți familiari încă cu termenul de “GPU Computing” (utilizarea unui procesor grafic pentru accelerarea calculelor), dar probabil ați exploatat una dintre întrebuințările ei, mai exact jocurile video. | ||
- | - (**6p**) Implementați o **tabelă de dispersie** generică care va permite să stocaţi perechi de tip cheie-valoare. | + | Jocurile video sunt create cu ajutorul unor engine-uri grafice, care în esență nu reprezintă altceva decât aplicații care realizează o multitudine de operații matematice: plotări de grafice, interpolări, operații matriceale/vectoriale, derivări etc. |
- | * (**2p**) Scrieţi antetul clasei ''MyHashMap'' şi prototipul funcţiilor **put** şi **get**. Aveţi grijă la parametrizarea tipurilor. | + | |
- | * (**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. | + | |
- | * (**1p**) Implementaţi metoda **get**. | + | |
- | * (**1p**) Testaţi implementarea voastră folosind o clasă definită de voi, care suprascrie metoda **hashCode** din ''Object''. | + | |
- | - (**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 | + | |
- | * Scrieți **o metodă generică** ce primește o colecție generică cu elemente de tipul ''Sumabil'' și returnează suma tuturor elementelor din colecție. Trebuie să utilizați //bounded types//. Care trebuie să fie, deci, antetul metodei? | + | |
- | == Resurse == | + | Aceste operații matematice pot fi făcute pe diferite tipuri de date. O matrice poate acceptă int-uri (exemplu: camera jucătorului), float-uri / double-uri (exemplu: setarea opacității unei texturi), char-uri (exemplu: reprezentarea text box-urilor pentru dialog) etc. În loc să creem câte o clasă care să adere fiecărui tip, putem scrie o singură dată o clasă care să reprezinte o matrice și care să accepte mai multe tipuri de date prin genericitate. Acest lucru devine foarte util dacă dorim să creem o bibliotecă întreagă pentru operații matematice avansate (exemplu: Jscience), fără să ne repetăm codul doar pentru a crea clase și metode specifice unor tipuri de date. |
- | * <html><a class="media mediafile mf_pdf" href="/poo/laboratoare/genericitate?do=export_pdf">PDF laborator</a></html> | + | ==== Exerciții ==== |
- | ==Referinţe== | + | Scheletul laboratorului poate fi descărcat de aici: {{:poo-ca-cd:laboratoare:oop_lab10.zip|}} |
- | * [[:poo-ca-cd:https://docs.oracle.com/javase/tutorial/java/generics/types.html | Generic Types]] | + | Laboratorul trebuie rezolvat pe platforma LambdaChecker, fiind găsit [[https://beta.lambdachecker.io/contest/21 | aici]]. |
- | * [[:poo-ca-cd:https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html | Wildcards]] | + | |
- | * [[:poo-ca-cd:https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html | Upper Bounded Wildcards]] | + | - **(6 puncte)** Implementați o structură de date de tipul ''MultiMapValue<K, V>'', pe baza scheletului, care reprezintă un ''HashMap<K, ArrayList<V>>'', unde o cheie este asociată cu mai multe valori. Modalitatea de stocare a datelor este la alegere (moștenire sau agregare) și să folosiți funcționalitățile din HashMap. În schelet aveți următoarele metode de implementat: |
- | * [[:poo-ca-cd:https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html | Lower Bounded Wildcards]] | + | - **(1 punct)** ''add(K key, V value)'' - adaugă o valoare la o cheie dată (valoarea este adăugate în lista de valori asociate cheii, dacă cheia și lista nu există, atunci lista va fi creată și asociată cheii. |
- | * [[:poo-ca-cd:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html | Type Erasure]] | + | - **(1 puncte)** ''void addAll(K key, List<V> values)'' - adaugă valorile din lista de valori dată ca parametru la lista asociată cheii. |
+ | - **(1 puncte)** ''void addAll(MultiMapValue<K, V> map)'' - adaugă intrările din obiectul MultiMapValue dat ca parametru în obiectul curent (this). | ||
+ | - **(0.5 puncte)** ''V getFirst(K key)'' - întoarce prima valoare asociată cheii (dacă nu există, se întoarce null). | ||
+ | - **(0.5 puncte)** ''List<V> getValues(K key)'' - se întoarce lista de valori asociată cheii. | ||
+ | - **(0.5 puncte)** ''boolean containsKey(K key)'' - se verifică faptul dacă este prezentă cheia în MultiMapValue. | ||
+ | - **(0.5 puncte)** ''boolean isEmpty()'' - se verifică dacă MultiMapValue este gol. | ||
+ | - **(0.5 puncte)** ''List<V> remove(K key)'' - se șterge cheia, împreună cu valorile asociate ei, din MultiMapValue. | ||
+ | - **(0.5 puncte)** ''int size()'' - se întoarce mărimea MultiMapValue. | ||
+ | |||
+ | - **(4 puncte)** Implementați o structură de date de tipul Tree<T> (Arbore binar de căutare) pe baza scheletului. Analizați modalitatea de utilizare a bounded wildcards, explicați necesitatea lor laborantului (fie în cadrul orei de laborator, fie la nivel de comentariu în cod). În schelet aveți următoarele metode de implementat: | ||
+ | - **(1 puncte)** ''void addValue(T value)'' - adaugă o valoare în arborele binar de căutare. | ||
+ | - **(0.5 puncte)** ''void addAll(List<T> values)'' - adaugă valorile dintr-o listă în arborele binar de căutare. | ||
+ | - **(1.5 puncte)** ''HashSet<T> getValues(T inf, T sup)'' - colectează valorile din arbore între o limită inferioară și superioară într-o colecție de tipul HashSet. | ||
+ | - **(0.5 puncte)** ''int size()'' - se întoarce numărul de elemente inserate în arbore. | ||
+ | - **(0.5 puncte)** ''boolean isEmpty()'' - se întoarce dacă există vreun element inserat în arborele binar sau nu. | ||
+ | |||
+ | ====Referinţe==== | ||
+ | |||
+ | * [[https://docs.oracle.com/javase/tutorial/java/generics/types.html | Generic Types]] | ||
+ | * [[https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html | Wildcards]] | ||
+ | * [[https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html | Upper Bounded Wildcards]] | ||
+ | * [[https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html | Lower Bounded Wildcards]] | ||
+ | * [[https://docs.oracle.com/javase/tutorial/java/generics/erasure.html | Type Erasure]] |