Differences

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

Link to this comparison view

poo-ca-cd:laboratoare:agregare-mostenire [2023/10/21 18:06]
alexandra.nioata [Utilizarea clasei ArrayList. Exemple]
poo-ca-cd:laboratoare:agregare-mostenire [2024/10/20 22:48] (current)
alexandra.nioata
Line 24: Line 24:
   * la **definirea** obiectului (înaintea constructorului:​ folosind fie o valoare inițială, fie blocuri de inițializare) ​   * la **definirea** obiectului (înaintea constructorului:​ folosind fie o valoare inițială, fie blocuri de inițializare) ​
   * în cadrul **constructorului** ​   * în cadrul **constructorului** ​
-  * chiar **înainte de folosire** (acest mecanism se numește inițializare leneșă (//lazy initialization//​))+  * chiar **înainte de folosire** (acest mecanism se numește inițializare leneșă (//lazy initialization//​)
  
 Exemple de cod: Exemple de cod:
Line 577: Line 577:
 În exemplul de mai sus, la declararea unui ArrayList, se observă semnele "<>",​ utilizate pentru a specifica tipul de date al elementelor,​ pe care ArrayList le va conține. Acest lucru se numește genericitate și permite compilatorului să verifice în timpul compilării că se folosește tipul corect de date. Conceptul de genericitate se va studia mai mult în [[https://​ocw.cs.pub.ro/​courses/​poo-ca-cd/​laboratoare/​genericitate|laboratorul 10]] . În exemplul de mai sus, la declararea unui ArrayList, se observă semnele "<>",​ utilizate pentru a specifica tipul de date al elementelor,​ pe care ArrayList le va conține. Acest lucru se numește genericitate și permite compilatorului să verifice în timpul compilării că se folosește tipul corect de date. Conceptul de genericitate se va studia mai mult în [[https://​ocw.cs.pub.ro/​courses/​poo-ca-cd/​laboratoare/​genericitate|laboratorul 10]] .
 </​note>​ </​note>​
 +
 +==== Cuvântul-cheie "​final"​. Obiecte immutable ====
 +
 +Variabilele declarate cu atributul ''​final''​ pot fi inițializate **o singură dată**. Observăm că astfel unei variabile de tip referință care are atributul ''​final''​ îi poate fi asignată o singură valoare (variabila poate puncta către un singur obiect). O încercare nouă de asignare a unei astfel de variabile va avea ca efect generarea unei erori la compilare.
 +
 +Totuși, obiectul către care punctează o astfel de variabilă poate fi modificat intern, prin apeluri de metode sau acces la câmpuri.
 +
 +Exemplu: ​
 +
 +<code java5>
 +class Student {
 +
 +    private final Group group; ​                     // a student cannot change the group he was assigned in
 +    private static final int UNIVERSITY_CODE = 15;  // declaration of an int constant
 +
 +    public Student(Group group) {
 +        // reference initialization;​ any other attempt to initialize it will be an error
 +        this.group = group;
 +    }
 +}
 +</​code>​
 +
 +Dacă toate atributele unui obiect admit o unică inițializare,​ spunem că obiectul respectiv este ''​immutable'',​ în sensul că //nu putem schimba obiectul in sine (informația pe care o stochează, de exemplu), ci doar referința către un alt obiect.//. Exemple de astfel de obiecte sunt instanțele claselor ''​String''​ și ''​Integer''​. Odată create, prelucrările asupra lor (ex.: ''​toUpperCase()''​) se fac prin **instanțierea de noi obiecte** și nu prin alterarea obiectelor înseși.
 +
 +Exemplu:
 +
 +<code java5>
 +String s1 = "​abc";​
 +
 +String s2 = s1.toUpperCase(); ​ // s1 does not change; the method returns a reference to a new object which can be accessed using s2 variable
 +s1 = s1.toUpperCase(); ​        // s1 is now a reference to a new object
 +</​code>​
 +<note tip>
 +Observăm că în acest exemplu am folosit un String literal. Literalii sunt păstrați într-un ''​String pool''​ pentru a limita memoria utilizată. Asta înseamnă că dacă mai declarăm un alt literal "​abc",​ nu se va mai aloca memorie pentru încă un String, ci vom primi o referință către s-ul inițial. În cazul în care folosim constructorul pentru String, se alocă memorie pentru obiectul respectiv și primim o referință nouă.
 +Pentru a evidenția concret cum funcționează acest ''​String pool'',​ să luăm următorul exemplu:
 +</​note>​
 +<code java5>
 +String s1 = "​a"​ + "​bc";​
 +String s2 = "​ab"​ + "​c";​
 +</​code>​
 +În momentul în care compilatorul va încerca să aloce memorie pentru cele 2 obiecte, va observa că ele conțin, de fapt, aceeași informație. Prin urmare, va instanția un singur obiect, către care vor pointa ambele variabile, s1 și s2. Observați că această optimizare (de a reduce memoria) e posibilă datorită faptului că obiectele de tip String sunt **immutable**.
 +
 +O întrebare legitimă este, așadar, cum putem compara două String-uri (ținând cont de faptul că avem referințele către ele, cum am arătat mai sus). Să urmărim codul de mai jos:
 +
 +<code java5>
 +String a = "​abc";​
 +String b = "​abc";​
 +System.out.println(a == b);  // True
 +
 +String c = new String("​abc"​);​
 +String d = new String("​abc"​);​
 +System.out.println(c == d);  // False
 +</​code>​
 +
 +<note important>​
 +Operatorul <​nowiki>"​=="</​nowiki>​ compară //​referințele//​. Dacă am fi vrut să comparăm șirurile în sine am fi folosit metoda ''​equals''​. Același lucru este valabil și pentru oricare alt tip de referință:​ operatorul <​nowiki>"​=="</​nowiki>​ testează egalitatea //​referințelor//​ (i.e. dacă cei doi operanzi sunt de fapt același obiect).
 +
 +
 +Dacă vrem să testăm "​egalitatea"​ a două obiecte, se apelează metoda: ''​public boolean equals(Object obj)''​.
 +
 +Reţineţi semnătura acestei metode!
 +</​note>​
 +O consecință a faptului că obiectele de tip String sunt imutabile este determinată de faptul că efectuarea de modificări succesive conduce la crearea unui număr foarte mare de obiecte in String pool.
 +<code java5>
 +public static String concatenationUsingTheStringClass() {  ​
 +   ​String t = "​Java";  ​
 +   for (int i = 0; i < 10000; i++) {  ​
 +      t = t + "​POO";  ​
 +   ​}  ​
 +   ​return t;  ​
 +}  ​
 +</​code>​
 +În acest caz, numărul de obiecte create în memorie este unul foarte mare. Dintre acestea doar cel rezultat la final este util. Pentru a preveni alocarea nejustificată a obiectelor de tip String care reprezintă pași intermediari în obținerea șirului dorit putem alege să folosim clasa StringBuilder creată special pentru a efectua operații pe șiruri de caractere.
 +<code java5>
 +public static String concatenationUsingTheStringBuilderClass() {  ​
 +   ​StringBuilder sb = new StringBuilder("​Java"​);  ​
 +   for (int i = 0; i < 10000; i++) {  ​
 +        sb.append("​POO"​);  ​
 +   ​}  ​
 +   ​return sb.toString();  ​
 +}
 +</​code>​
 +
 +Cuvântul cheie final poate fi folosit și în alt context decât cel prezentat anterior. De exemplu, aplicat unei clase împiedică o eventuală derivare a acestei clase prin moștenire.
 +<code java5>
 +final class ParentClass {
 +}
 +
 +class ChildClass extends ParentClass {
 +    // compilation error, the class ParentClass cannot be extended
 +}
 +</​code>​
 +
 +În mod similar, în cazul în care aplicăm cuvântul cheie final unei metode, acest lucru împiedică o eventuală suprascriere a acelei metode.
 +<code java5>
 +class ParentClass {
 +   ​public final void dontOverride() {
 +        System.out.println("​You cannot override this method"​);​
 +   }
 +}
 +
 +class ChildClass extends ParentClass {
 +    public void dontOverride() {               // compilation error, the method dontOverride() from
 +        System.out.println("​But I want to!"​); ​ // the parent class cannot be overriden
 +    }
 +}
 +</​code>​
   ​   ​
 ====Summary==== ====Summary====
Line 607: Line 714:
  
 <note important>​ <note important>​
-Veti încărca soluția ​voastră pe LambdaCheckercontest [[https://beta.lambdachecker.io/contest/11 | POO LAB3]]+Pentru a încărca soluția, ​va trebui să accesați link-ul ​https://code.devmind.ro/login, să intrați pe tab-ul Contests, unde veți găsi laboratorul grupei voastre.
  
-Încercați să accesați de aici contest-ul, altfel e posibil să vă ceară o parolă care nu există. De asemena, să fiți logați pe LambdaChecker înainte de accesa link-ul. m( 
 </​note>​ </​note>​
-Pentru acest laborator este de recomandat să creați un pachet numit ''​lab3'',​ unde veți face subpachete pentru task-uri. 
  
-Gigel vrea să-i facă mamei sale un cadou de ziua ei și știe că-i plac foarte mult bomboanele. El are nevoie de ajutorul vostru pentru a construi cel mai frumos și gustos cadou: +**Task 1 [1p]**
-   +
-**Task 1** [2p] +
- +
-Veți proiecta o clasă CandyBox, care va conține câmpurile private flavor (String) și origin (String). ​+
  
 +Veți proiecta o clasă Form care va avea câmpul privat color (String).
  
 Clasa va avea, de asemenea: Clasa va avea, de asemenea:
-  * un constructor fără parametri ce va inițializa câmpurile cu "​sugar-free",​ respectiv "​Switzerland"​ 
-  * un constructor cu parametri 
-  * o metodă de tip float getVolume(),​ care va întoarce valoarea 0; 
-  * o metodă toString(), care va returna flavor-ul și regiunea de proveniență a cutiei de bomboane ("The [flavor] [origin] chocolate"​). 
  
-**Task 2** [2p] 
  
-Din clasa CandyBox ​derivați clasele ​LindtBaravelliChocAmor+- un constructor fără parametri, care va inițializa culoarea cu “white”;​ 
 + 
 +- un constructor cu parametri;​ 
 + 
 +- o metodă de tip float getArea(), care va întoarce valoarea 0; 
 + 
 +- o metodă toString(): “This form has the color [color]”. 
 + 
 + 
 +**Task 2 [2p]** 
 + 
 +Din clasa Form derivați clasele ​SquareTriangleCircle: 
 + 
 +- clasa Triangle (triunghi isoscel) va avea 2 membri height și base (adiacenta unghiurilor congruente) de tip float; 
 + 
 +- clasa Circle va avea membrul radius de tip float; 
 + 
 +- clasa Square va avea membrul side de tip float.
  
-Pentru un design interesant, cutiile vor avea forme diferite: 
-  * Lindt va conține length, width, height (float); 
-  * Baravelli va fi un cilindru. Acesta va conține un câmp radius și unul height (float); 
-  * ChocAmor, fiind un cub, va conține un camp length (float). 
  
 Clasele vor avea: Clasele vor avea:
-  * constructori fără parametri ​ce vor initializa cu 0.0 campurile float; +constructori fără parametri;
-  * constructori cu parametri (Identificați o modalitate de reutilizare a codului existent. Pentru fiecare tip de cutie veți inițializa,​ în constructor,​ câmpurile flavor și origin cu tipul corespunzător);​ +
-  * Suprascrieți metoda getVolume() pentru a întoarce volumul specific fiecărei cutii de bomboane, în funcție de tipul său; +
-  * Suprascrieți metoda toString() în clasele derivate, astfel încât aceasta să utilizeze implementarea metodei toString() din clasa de bază. Returnați un mesaj de forma "​Lindt/​Baravelli/​Chocamor (*in functie de clasa de care apartine metoda): The [origin] [flavor] chocolate has volume [volume]"​.+
  
-**Task 3** [1p] +- constructori care permit inițializarea membrilor. Identificați o modalitate de reutilizare a codului existent;
- +
  
-Adăugați o metodă equals() în clasa CandyBox. ​+- suprascrieți metoda getArea() pentru a întoarce aria specifică fiecărei figuri geometrice;
  
-Justificați criteriul de echivalentă ales+- suprascrieți metoda toString() în clasele derivate, astfel încât aceasta să utilizeze implementarea metodei toString() din clasa de baza.
  
-Creați obiecte de tip Lindt și testați egalitatea lor. 
-<note important>​**Hint:​** 
-Puteți genera automat metoda, cu ajutorul IDE. Selectați câmpurile considerate și 
-analizați în ce fel va fi suprascrisă metoda equals.</​note>​ 
  
-**Task ​4** - //''​Upcasting''// ​[2p]+**Task ​[2p]**
  
-Acum că am stabilit tipul cutiilor de bomboane, putem construi un cadou default care va contine in aceasta ordine: +Adăugați ​metodă equals() în clasa Triangle.
-  * 3 cutii Lindt: Austria cherry, Austria apricot , Austria strawberry, toate cu dimensiunile length 20, width 5.4, height 19.2 +
-  * cutie Baravelli: Italy grape, radius 6.7, height 8.7 +
-  * 2 cutii ChocAmor: France coffee, France vanilla, ambele cu length 5.+
  
-Creați o clasă CandyBag, care va conține un ArrayList populat cu lista de mai sus.+Justificați criteriul ​de echivalență ales.
  
 +Hint: Puteți genera automat metoda, cu ajutorul IDE. Selectați câmpurile considerate și analizați în ce fel va fi suprascrisă metoda equals.
  
-În pachetul java.util se găsește clasa ''​ArrayList'',​ care definește un resizable array, cu metodele specifice (add, size, get, lista lor completa este în [[https://​docs.oracle.com/​en/​java/​javase/​12/​docs/​api/​java.base/​java/​util/​ArrayList.html|documentatie]]). Creați o clasă ''​CandyBag'',​ care va conține un ArrayList cu mai multe cutii din fiecare tip.+**Task 4 - Upcasting ​[1p]**
  
 +Creați un vector de obiecte Form și populați-l cu obiecte de tip Triangle, Circle și Square (upcasting). ​
  
-**Task 5** - //''​Downcasting''//​ [1p]+Parcurgeți acest vector și apelați metoda toString() pentru elementele sale. Ce observați?
  
-Adăugați clasei Baravelli, funcția printBaravelliDim(),​ care va afișa dimensiunile razei și înălțimii. În mod analog, procedați cu celelalte tipuri de cutii, adaugând metodele printChocAmorDim() și printLindtDim(),​ în care să afișați dimensiunile fiecărei cutii.+**Task 5 - Downcasting [2p]**
  
-**Task 6** - //''​Agregare''//​ [2p]+Adăugați:
  
-Gigel va vrea sa trimită prin curier cadoul, pentru a nu-l găsi mama lui mai devreme. Ajutați-l să determine locația, creând clasa “Area”, care va conține un obiect de tip CandyBag, un câmp “number” (int)un câmp “street” (String) si un camp "​message"​ (String).+clasei Triangle metoda printTriangleDimensions,
  
-Clasa va avea, de asemenea: +- clasei Circle metoda printCircleDimensions
-  * un constructor fără parametri ce va initializa campurile cu 0, respectiv "​nowhere";​ +
-  * un constructor cu parametri.+
  
-Acum ca am finalizat construcția,​ îi vom oferi mamei informații despre cadoul ei printr-o felicitare:​ +clasei Square ​metoda ​printSquareDimensions
-  * Creați o metoda ​getBirthdayCard(),​ care va afișa, pe primul rand, adresa completă, iar apoi un mesaj de la multi ani. +
-  * Tot aici, parcurgeți array-ul, apelând metoda toString() pentru elementele sale.+
  
-Parcurgeți array-ul ​și, folosind downcasting la clasa corespunzătoareapelați metodele specifice fiecărei clase+Implementarea metodelor constă în afișarea bazei și înălțimiirazei, respectiv laturii.
  
-Pentru a stabili tipul obiectului curent folosiți operatorul **instanceof**. 
  
-<note important>​ +Parcurgeți vectorul de la exercițiul anterior ​și, folosind downcasting la clasa corespunzătoare, apelați metodele specifice fiecărei clase: 
-În final, modificați cum considerați programul ​anterior ​astfel încât să nu mai aveți nevoie de instanceof ​(getBirtdayCardv2() method).</​note>​+ 
 + 
 +- printTriangleDimensions pentru Triangle 
 + 
 +- printCircleDimensions pentru Circle 
 + 
 +- printSquareDimensions pentru Square 
 + 
 +Pentru a stabili tipul obiectului curent folosiți operatorul ​instanceof. 
 + 
 +**Task 6 - Agregare [1p]** 
 + 
 +Afișați dimensiunile formelor din vectorul creat fără a folosi operatorul instanceof. 
 + 
 +**Task 7 - Final [1p]** 
 + 
 +Afișați perimetrul fiecărui obiect din vectorul creat utilizând exclusiv funcția printPerimeter,​ modificând doar ce se afla in corpul funcției, lasând antetul identic. 
  
 ==== Resurse ==== ==== Resurse ====
poo-ca-cd/laboratoare/agregare-mostenire.1697900795.txt.gz · Last modified: 2023/10/21 18:06 by alexandra.nioata
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