Differences

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

Link to this comparison view

poo-ca-cd:laboratoare:agregare-mostenire [2020/10/03 13:58]
radu_bogdan.pavel [Summary]
poo-ca-cd:laboratoare:agregare-mostenire [2024/10/20 22:48] (current)
alexandra.nioata
Line 1: Line 1:
-===== Agregare și moștenire =====+===== Laboratorul 3: Agregare și moștenire =====
  
 +**Video introductiv:​** [[https://​www.youtube.com/​watch?​v=Gb-p4tMrdBM|link]]
  
 ==== Obiective ==== ==== Obiective ====
Line 23: 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 30: Line 31:
 <code java> <code java>
 public class Foo { public class Foo {
-    // Obiectul Bar nu poate exista dacă obiectul Foo nu există+    // Obiectul ​de tip Bar nu poate exista dacă obiectul Foo nu există
     private Bar bar = new Bar();     private Bar bar = new Bar();
 } }
Line 39: Line 40:
     private Bar bar;      private Bar bar; 
     ​     ​
-    // Obiectul Bar poate continua să existe chiar dacă obiectul Foo nu există+    // Obiectul ​de tip Bar poate continua să existe chiar dacă obiectul Foo nu există
     Foo(Bar bar) {     Foo(Bar bar) {
        ​this.bar = bar;         ​this.bar = bar; 
Line 123: Line 124:
 ====Upcasting și Downcasting==== ====Upcasting și Downcasting====
  
-**Convertirea** unei referințe la o clasă derivată într-una a unei clase de bază poartă numele de **upcasting**. Upcasting-ul este facut **automat** și **nu** trebuie declarat explicit de către programator.+**Convertirea** unei referințe la o clasă derivată într-una a unei clase de bază poartă numele de **upcasting**. Upcasting-ul este făcut ​**automat** și **nu** trebuie declarat explicit de către programator.
  
 {{:​poo-ca-cd:​laboratoare:​agregare-mostenire:​upcast-downcast.png?​nolink&​400|}} {{:​poo-ca-cd:​laboratoare:​agregare-mostenire:​upcast-downcast.png?​nolink&​400|}}
Line 140: Line 141:
  
 // Obiectele Wind sunt instrumente // Obiectele Wind sunt instrumente
-// deoarece au aceeași interfață:​+// deoarece au ca și clasa-parinte clasa Instrument
 public class Wind extends Instrument { public class Wind extends Instrument {
     public static void main(String[] args) {     public static void main(String[] args) {
Line 182: Line 183:
 } }
  
-class Test {+public ​class Test {
     public static void main(String[] args) {     public static void main(String[] args) {
-        Animal ​[] = new Animal[2]; +        Animal[] ​animals ​= new Animal[2];
-         +
-        a[0] = new Wolf(); ​   // Upcasting automat +
-        a[1] = new Snake(); ​  // Upcasting automat+
  
-        for (int i = 0; i < a.length; i++) { +        ​animals[0] = new Wolf(); ​   // Upcasting automat 
-            ​a[i].eat(); // 1 +        animals[1] = new Snake(); ​  // Upcasting automat 
-             + 
-            if (a[i] instanceof Wolf) { +        ​for (int i = 0; i < animals.length; i++) { 
-                ((Wolf)a[i]).howl();​ // 2+            ​animals[i].eat(); // 1 
 + 
 +            if (animals[i] instanceof Wolf) { 
 +                ((Wolf)animals[i]).howl();​ // 2
             }             }
-                ​ + 
-            if (a[i] instanceof Snake) { +            if (animals[i] instanceof Snake) { 
-                ((Snake)a[i]).bite();​ // 3+                ((Snake)animals[i]).bite();​ // 3
             }             }
         }         }
     }     }
-+}
 </​code>​ </​code>​
  
Line 214: Line 215:
  
   ​   ​
-În liniile marcate cu **2** și **3** se execută un downcast de la ''​Animal''​ la ''​Wolf'',​ respectiv ''​Snake''​ pentru a putea fi apelate metodele specifice definite în aceste clase. Înaintea execuției downcast-ului (conversia de tip la Wolf respectiv Snake) verificăm dacă obiectul respectiv este de tipul dorit (utilizând operatorul ''​**instanceof**''​). Dacă am încerca să facem downcast către tipul ''​Wolf''​ al unui obiect ​instantiat ​la ''​Snake''​ mașina virtuală ar semnala acest lucru aruncând o excepție la rularea programului. ​+În liniile marcate cu **2** și **3** se execută un downcast de la ''​Animal''​ la ''​Wolf'',​ respectiv ''​Snake''​ pentru a putea fi apelate metodele specifice definite în aceste clase. Înaintea execuției downcast-ului (conversia de tip la Wolf respectiv Snake) verificăm dacă obiectul respectiv este de tipul dorit (utilizând operatorul ''​**instanceof**''​). Dacă am încerca să facem downcast către tipul ''​Wolf''​ al unui obiect ​instanțiat ​la ''​Snake''​ mașina virtuală ar semnala acest lucru aruncând o excepție la rularea programului. ​
   ​   ​
-Apelarea metodei ''​eat()''​ (linia **1**) se face direct, fără downcast, deoarece această metodă este definită și în clasa de bază ''​Animal''​. Datorită faptului că ''​Wolf''​ suprascrie (//​overrides//​) metoda ''​eat()'',​ apelul ''​a[0].eat()''​ va afișa "Wolf eating"​. Apelul ''​a[1].eat()''​ va apela metoda din clasă de bază (la ieșire va fi afișat "​Animal eating"​) deoarece ''​a[1]''​ este instantiat ​la ''​Snake'',​ iar ''​Snake''​ nu suprascrie metoda ''​eat()''​. ​+Apelarea metodei ''​eat()''​ (linia **1**) se face direct, fără downcast, deoarece această metodă este definită și în clasa de bază ''​Animal''​. Datorită faptului că ''​Wolf''​ suprascrie (//​overrides//​) metoda ''​eat()'',​ apelul ''​a[0].eat()''​ va afișa "Wolf eating"​. Apelul ''​a[1].eat()''​ va apela metoda din clasă de bază (la ieșire va fi afișat "​Animal eating"​) deoarece ''​a[1]''​ este instanțiat ​la ''​Snake'',​ iar ''​Snake''​ nu suprascrie metoda ''​eat()''​. ​
   ​   ​
 <note important>​Upcasting-ul este un element foarte important. De multe ori răspunsul la întrebarea:​ //este nevoie de moștenire?//​ este dat de răspunsul la întrebarea:​ //am nevoie de upcasting?//​ Aceasta deoarece upcasting-ul se face atunci când pentru unul sau mai multe obiecte din clase derivate se execută aceeași metodă definită în clasa părinte.</​note> ​ <note important>​Upcasting-ul este un element foarte important. De multe ori răspunsul la întrebarea:​ //este nevoie de moștenire?//​ este dat de răspunsul la întrebarea:​ //am nevoie de upcasting?//​ Aceasta deoarece upcasting-ul se face atunci când pentru unul sau mai multe obiecte din clase derivate se execută aceeași metodă definită în clasa părinte.</​note> ​
Line 222: Line 223:
 ===Să încercăm să evităm folosirea instanceof=== ===Să încercăm să evităm folosirea instanceof===
  
-Totuși, deși v-am ilustrat cum ''​instanceof''​ ne poate ajuta să ne dăm seama la ce să facem **downcasting**,​ este de preferat să ne organizăm clasele și designul codului în așa fel încât să lăsăm limbajul Java să facă automat verificarea tipului și să cheme metoda corespunzătoare. Vom refactororiza ​codul anterior pentru a nu fi nevoie de ''​instanceof'':​+Totuși, deși v-am ilustrat cum ''​instanceof''​ ne poate ajuta să ne dăm seama la ce să facem **downcasting**,​ este de preferat să ne organizăm clasele și designul codului în așa fel încât să lăsăm limbajul Java să facă automat verificarea tipului și să cheme metoda corespunzătoare. Vom refactoriza ​codul anterior pentru a nu fi nevoie de ''​instanceof'':​
  
 <code java5> <code java5>
Line 281: Line 282:
 Snake biting Snake biting
 </​code>​ </​code>​
 +
 +===De ce este instanceof considerat bad practice?​===
 +  * face codul repetitiv - downcasting și apelare de metodă la fiecare branch de if/else
 +  * face codul mai greu de întreținut pe termen lung - codul principal trebuie updatat de fiecare dată când se introduce o nouă subclasă (vezi exemplul de mai sus - introducerea unui noi clase derivate din  Animal va determina un alt branch de if/else)
 +  * face codul mai dificil de citit - este mult mai ușor să ne uităm la metodele suprascrise cu tag-ul @Override decât să căutam fiecare metoda cu un nume diferit pe rând
 +  * distruge designul orientat-obiect din perspectiva polimorfismului
 +  * încalcă [[https://​www.baeldung.com/​java-open-closed-principle|open-closed principle]]
 +  * nu poate fi folosit cu tipuri generice, ''​instanceof''​ fiind un **type comparison operator** ce va compara la runtime, în schimb genericitatea fiind rezolvată la compile-time. Mai multe detalii [[https://​www.baeldung.com/​java-instanceof#​generics|aici]] si in [[https://​ocw.cs.pub.ro/​courses/​poo-ca-cd/​laboratoare/​genericitate|laboratorul 10]] despre genericitate.
 +
 +**Soluții** pentru evitarea ''​instanceof'':​
 +   * polimorfism
 +   * [[https://​ocw.cs.pub.ro/​courses/​poo-ca-cd/​laboratoare/​visitor|Visitor]]
 +
 +
 +<note important>​
 +Când este necesar să folosim ''​instanceof''?​
 +
 +''​instanceof''​ poate fi folosit când nu controlăm ierarhia claselor și suntem obligați să facem
 +testarea tipului deoarece nu putem aplica polimorfismul - clasele provin dintr-o librărie externă.
 +</​note>​
  
   ​   ​
Line 357: Line 378:
 b.print(); // afișează Car pentru că tipul dat la inițializare al lui b este Car b.print(); // afișează Car pentru că tipul dat la inițializare al lui b este Car
 c.print(); // afișează Dacia pentru că tipul dat la inițializare al lui c este  Dacia c.print(); // afișează Dacia pentru că tipul dat la inițializare al lui c este  Dacia
-d.print(): // afișează Car pentru că tipul dat la inițializare al lui este Car+d.print(): // afișează Car pentru că tipul dat la inițializare al lui este Car
 </​code>​ </​code>​
  
Line 364: Line 385:
 <note warning>​Sintaxa Java permite apelarea metodelor statice pe instanțe (e.g. a.print în loc de Car.print), dar acest lucru este considerat bad practice pentru că poate îngreuna înțelegerea codului.</​note>​ <note warning>​Sintaxa Java permite apelarea metodelor statice pe instanțe (e.g. a.print în loc de Car.print), dar acest lucru este considerat bad practice pentru că poate îngreuna înțelegerea codului.</​note>​
  
-===Suprascrierea ​corecta ​a metodei equals(Object o)===+===Suprascrierea ​corectă ​a metodei equals(Object o)===
  
 Una din problemele cele mai des întâlnite este suprascrierea corectă a metodei //equals//. Mai jos putem vedea un exemplu de suprascriere incorectă a acestei metode. Una din problemele cele mai des întâlnite este suprascrierea corectă a metodei //equals//. Mai jos putem vedea un exemplu de suprascriere incorectă a acestei metode.
Line 387: Line 408:
 Car a = new Car(); Car a = new Car();
 Dacia b = new Dacia(); Dacia b = new Dacia();
-Int c = new Int(10);+int c = 10;
  
 a.equals(a);​ // afișează Car a.equals(a);​ // afișează Car
Line 394: Line 415:
 </​code>​ </​code>​
  
-Problema care se poate observa este că putem pasa ca argumente metodei equals si tipuri de date diferite de ''​Car'',​ lucru ce ar putea arunca excepții de cast sau când vrem să accesăm anumite proprietăți din instanță. Mai jos este modul corect de suprascrie metoda equals.+Problema care se poate observa este că putem pasa ca argumente metodei equals si tipuri de date diferite de ''​Car'',​ lucru ce ar putea arunca excepții de cast sau când vrem să accesăm anumite proprietăți din instanță. Mai jos este modul corect de suprascrie metoda equals.
  
 <code java> <code java>
Line 504: Line 525:
  
 <note important>​Chiar dacă nu se specifică apelul metodei ''​super()'',​ compilatorul va apela automat constructor-ul implicit al părintelui însă dacă se dorește apelarea altui constructor,​ apelul de ''​super(args)''​ respectiv este obligatoriu</​note>​ <note important>​Chiar dacă nu se specifică apelul metodei ''​super()'',​ compilatorul va apela automat constructor-ul implicit al părintelui însă dacă se dorește apelarea altui constructor,​ apelul de ''​super(args)''​ respectiv este obligatoriu</​note>​
 +
 +====Utilizarea clasei ArrayList. Exemple====
 +
 +Clasa ArrayList este un array redimensionabil,​ iar această clasă poate fi găsită în pachetul ''​java.util''​.
 +Principalele metode ale acestei clase sunt:
 +  * ''​add()''​ - adaugă un element la ArrayList.
 +  * ''​get()''​ - accesează elementul de pe o anumită poziție din ArrayList.
 +  * ''​size()''​ - returnează numărul de elemente din ArrayList.
 +  * ''​set()''​ - modifică un element de pe o anumită poziție din ArrayList. ​
 +  * ''​remove()''​ - șterge un element de pe o anumită poziție din ArrayList.
 +  * ''​clear()''​ - șterge toate elementele din ArrayList.
 +
 +Pentru a putea parcurge elementele unui ArrayList se poate folosit atât un for-each, cât și clasa Iterator.
 +Un exemplu de utilizare a metodelor clasei ArrayList și de parcurgere a elementelor stocate de această clasă este următorul:
 +
 +<code java5>
 +import java.util.ArrayList;​
 +import java.util.Iterator;​
 +
 +public class Main {
 +    public static void main(String[] args) { 
 +    ​
 +        ArrayList<​String>​ animals = new ArrayList<>​();​
 +        animals.add("​Dog"​);​
 +        animals.add("​Cat"​);​
 +        animals.add("​Sheep"​);​
 +    ​
 +        System.out.println("​First animal from the list is: " + animals.get(0));​
 +        System.out.println("​Number of animals from the list: " + animals.size());​
 +
 +        animals.set(0,​ "​Lion"​);​
 +        System.out.println("​First animal from the list is: " + animals.get(0));​
 +        ​
 +        animals.remove(0);​
 +        ​
 +        for (String animal : animals) {
 +            System.out.println(animal);​
 +        }
 +        ​
 +        Iterator iterator = animals.iterator();​
 +        while(iterator.hasNext()) {
 +            System.out.println(iterator.next());​
 +        }
 +        ​
 +        animals.clear(); ​
 +    }
 +}
 +</​code>​
 +
 +<note important>​
 +Î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>​
 +
 +==== 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 510: Line 690:
   * Moștenire - **is a**   * Moștenire - **is a**
  
-**Upcasting** ​+**Upcasting:** 
   * convertire **copil** => **părinte**   * convertire **copil** => **părinte**
   * realizată automat   * realizată automat
  
-**Downcasting**+**Downcasting:**
   * convertire **părinte** =>​**copil**   * convertire **părinte** =>​**copil**
   * trebuie făcută explicit de către programator   * trebuie făcută explicit de către programator
   * încercați să evitați folosirea operatorului **instanceof**   * încercați să evitați folosirea operatorului **instanceof**
  
-**Suprascrierea** ​+**Suprascrierea:** 
   * înlocuirea funcționalității metodei din clasa de bază în clasa derivată   * înlocuirea funcționalității metodei din clasa de bază în clasa derivată
   * păstreaza numele și semnătura metodei   * păstreaza numele și semnătura metodei
  
-**Supraincărcarea**  ​+**Supraîncărcarea:**  ​
   * în interiorul clasei pot exista mai multe metode cu același nume, cu condiția ca semnătura (tipul, argumentele) să fie diferită   * în interiorul clasei pot exista mai multe metode cu același nume, cu condiția ca semnătura (tipul, argumentele) să fie diferită
  
-**super**+**Cuvântul cheie super:**
   * instanța clasei părinte   * instanța clasei părinte
-  * amintiți-vă din laboratorul anterior că **[[:​poo-ca-cd:​laboratoare:​constructori-referinte#​cuvantul_cheie_this_intrebuintari]]** se referă la instanța clasei curente+  * amintiți-vă din laboratorul anterior că **[[:​poo-ca-cd:​laboratoare:​constructori-referinte#​cuvantul_cheie_this_intrebuintari|this]]** se referă la instanța clasei curente
  
  
 ====Exerciții==== ====Exerciții====
  
-Gigel vrea -faca mamei sale un cadou de ziua ei și știe că-i plac foarte mult bomboaneleEl are nevoie de ajutorul vostru pentru a construi cel mai frumos și gustos cadou: +<note important>​ 
-   +Pentru a încărca soluția, va trebui ​să accesațlink-ul https://​code.devmind.ro/​login,​ să intrați pe tab-ul Contests, unde vețgăsi laboratorul grupei voastre.
-**Task 1** [2p]+
  
-Veti proiecta o clasa ''​CandyBox'',​ care va conține câmpurile private ''​flavor''​ (String) și ''​origin''​ (String). Clasa va avea, de asemenea: +</​note>​
-                  * un constructor fără parametri +
-                  * un constructor ce va inițializa toate campurile +
-                  * o metoda de tip float ''​getVolume()'',​ care va intoarce valoarea 0; +
-                  * Întrucât clasa ''​Object''​ se află în rădăcina arborelui de moștenire pentru orice clasă, orice instanta va avea acces la o serie de facilități oferite de Object. Una dintre ele este metoda ''​toString()'',​ al cărei scop este de a oferi o reprezentare unei instanțe sub forma unui șir de  caractere, utilizata in momentul apelului System.out.println(). Adaugati o metoda ''​toString()'',​ care va returna flavor-ul si regiunea de proveniență a cutiei de bomboane.+
  
-**Task ​2** [2p]+**Task ​1 [1p]** 
 + 
 +Veți proiecta o clasă Form care va avea câmpul privat color (String). 
 + 
 +Clasa va avea, de asemenea: 
 + 
 + 
 +- 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 Square, Triangle, Circle: 
 + 
 +- 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.
  
-Din ea derivați clasele ''​Lindt'',​ ''​Baravelli'',​ ''​ChocAmor''​. Pentru un design interesant, cutiile vor avea forme diferite: 
-  * //Lindt// va contine ''​length'',​ ''​width'',​ ''​height''​ (float); 
-  * //​Baravelli//​ va fi un cilindru. Acesta va conține un camp ''​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 +constructori fără parametri;
-  * constructori care permit inițializarea membrilor. Identificați o modalitate de reutilizare a codului existent. Pentru fiecare tip de cutie veti initializa, in constructor,​ campurile ''​flavor''​ și ''​origin''​ cu tipul corespunzator +
-  * Suprascrieti metoda //​getVolume()//​ pentru a intoarce volumul specific fiecarei cutii de bomboane, in functie de tipul sau. +
-  * Suprascrieti ​ metoda //​toString()//​ în clasele derivate, astfel încat aceasta să utilizeze implementarea metodei toString() din clasa de bază. Returnați un mesaj de forma //"The " + origin + " " + flavor + " 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''​. Justificați criteriul de echivalentă ales. Vedeți metodele clasei [[https://​docs.oracle.com/​en/​java/​javase/​12/​docs/​api/​java.base/​java/​lang/​Object.html | Object]], moștenită de toate clasele - Object are metoda equals, a cărei implementare verifică echivalența obiectelor comparând referințele. +- suprascrieți metoda getArea() pentru a întoarce aria specifică fiecărei figuri geometrice;
-<note important>​**Hint:​** +
-Puteti 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]+suprascrieți metoda toString() în clasele derivate, astfel încât aceasta să utilizeze implementarea metodei toString() din clasa de baza.
  
-Acum că am stabilit tipul cutiilor de bomboane, putem construi cadoul, ramanand la latitudinea vostra care va fi designul lui. In pachetul java.util se gaseste clasa ''​ArrayList'',​ care definește un resizable array, cu metodele specifice (add, size, get, lista lor completa este in [[https://​docs.oracle.com/​en/​java/​javase/​12/​docs/​api/​java.base/​java/​util/​ArrayList.html|documentatie]]). Creati o clasă ''​CandyBag'',​ care va conține un ArrayList cu mai multe cutii din fiecare tip. Creați obiecte de tip Lindt si testați egalitatea lor; 
  
 +**Task 3 [2p]**
  
-**Task 5** - //''​Downcasting''//​ [1p]+Adăugați o metodă equals() în clasa Triangle.
  
-Adaugati clasei ''​Baravelli'',​ functia ''​printBaravelliDim()'',​ care va afișa dimensiunile razei șinaltimii. În mod analog, procedati cu celelalte tipuri ​de cutii, adaugand metodele ''​printChocAmorDim()''​ si ''​printLindtDim()'',​ în care să afișați dimensiunile fiecarei cutii.+Justificațcriteriul ​de echivalență ales.
  
-**Task ​6** - //''​Agregare''// ​[2p]+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. 
 + 
 +**Task ​4 - Upcasting [1p]** 
 + 
 +Creați un vector de obiecte Form și populați-l cu obiecte de tip Triangle, Circle și Square (upcasting).  
 + 
 +Parcurgeți acest vector și apelați metoda toString() pentru elementele sale. Ce observați?​ 
 + 
 +**Task 5 - Downcasting ​[2p]** 
 + 
 +Adăugați:​ 
 + 
 +- clasei Triangle metoda printTriangleDimensions,​ 
 + 
 +- clasei Circle metoda printCircleDimensions 
 + 
 +- clasei Square metoda printSquareDimensions 
 + 
 +Implementarea metodelor constă în afișarea bazei și înălțimii,​ razei, respectiv laturii. 
 + 
 + 
 +Parcurgeți vectorul de la exercițiul anterior și, folosind downcasting la clasa corespunzătoare,​ apelați metodele specifice fiecărei clase: 
 + 
 + 
 +- 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.
  
-Gigel va vrea sa trimită prin curier cadoul, pentru a nu-l gasi 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 camp "​number"​ (int) și un câmp "​street"​ (String) 
-Clasa va avea, de asemenea: 
-  * un constructor fără parametri 
-  * un constructor ce va inițializa toate campurile ​ 
-  * Acum ca am finalizat construcția,​ îi vom oferi mamei informații despre cadoul ei printr-o felicitare. 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, apeland metoda ''​toString()''​ pentru elementele sale. 
-  * Parcurgeți array-ul și, folosind downcasting la clasa corespunzătoare,​ apelați metodele specifice fiecărei clase. Pentru a stabili tipul obiectului curent folosiți operatorul ''​instanceof''​ 
-  * In final, modificați cum considerati programul anterior astfel încât să nu mai aveți nevoie de instanceof. 
  
 ==== Resurse ==== ==== Resurse ====
-/* {{:​poo-ca-cd:​laboratoare:​agregare-mostenire:​lab3-sol-2019.zip|Soluție}} */ +  ​* [[:​poo-ca-cd:​laboratoare:​old-exercises#​agregare_si_mostenire|Exerciții din alți ani]]
-  ​* [[:​poo-ca-cd:​laboratoare:​old-exercises|Exerciții din alți ani]]+
  
 ==== Referințe ==== ==== Referințe ====
- +  ​* [[https://​www.visual-paradigm.com/guide/​uml-unified-modeling-language/uml-class-diagram-tutorial/ | UML Diagrams]] 
-  ​* [[https://​www.journaldev.com/1325/composition-in-java-example/ | Composition Example]]+
   * [[https://​www.visual-paradigm.com/​guide/​uml-unified-modeling-language/​uml-aggregation-vs-composition/​ | Aggregation vs Composition]]   * [[https://​www.visual-paradigm.com/​guide/​uml-unified-modeling-language/​uml-aggregation-vs-composition/​ | Aggregation vs Composition]]
   * [[http://​docs.oracle.com/​javase/​tutorial/​java/​IandI/​subclasses.html | Inheritance JavaDoc]]   * [[http://​docs.oracle.com/​javase/​tutorial/​java/​IandI/​subclasses.html | Inheritance JavaDoc]]
 +  * [[https://​www.journaldev.com/​1775/​multiple-inheritance-in-java | Multiple Inheritance]]
   * [[http://​forum.codecall.net/​topic/​50451-upcasting-downcasting/​ | Upcasting and Downcasting]]   * [[http://​forum.codecall.net/​topic/​50451-upcasting-downcasting/​ | Upcasting and Downcasting]]
  
poo-ca-cd/laboratoare/agregare-mostenire.1601722723.txt.gz · Last modified: 2020/10/03 13:58 by radu_bogdan.pavel
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