This shows you the differences between two versions of the page.
poo:breviare:breviar-03 [2018/09/22 10:36] mihai.nan |
poo:breviare:breviar-03 [2023/10/16 19:36] (current) carmen.odubasteanu [Laborator 3 - Clase și Obiecte în Java] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Breviar ====== | ====== Breviar ====== | ||
===== Laborator 3 - Clase și Obiecte în Java ===== | ===== Laborator 3 - Clase și Obiecte în Java ===== | ||
- | + | ==== Introducere ==== | |
- | * Responsabil: [[mihai.nan.cti@gmail.com|Mihai Nan]] | + | |
- | * Profesor titular: Carmen Odubășteanu | + | |
- | + | ||
- | === Introducere === | + | |
Presupunem că dorim //să descriem//, uzitând un limbaj de programare, un **obiect** carte. În general, o carte poate fi caracterizată prin titlu, autor și editură. Cum am putea realiza această descriere formală? | Presupunem că dorim //să descriem//, uzitând un limbaj de programare, un **obiect** carte. În general, o carte poate fi caracterizată prin titlu, autor și editură. Cum am putea realiza această descriere formală? | ||
Line 58: | Line 54: | ||
<note tip>Se poate observa cu usurință, în cadrul exemplului de mai sus, că atât datele cât și **metodele** (funcțiile) care operează asupra acestora se găsesc în interiorul aceleiași entități, numită **clasa**. Evident, în codul din exemplu sunt folosite concepte care nu au fost încă explicate, dar cunoașterea și înțelegerea lor reprezintă scopul principal al acestui laborator.</note> | <note tip>Se poate observa cu usurință, în cadrul exemplului de mai sus, că atât datele cât și **metodele** (funcțiile) care operează asupra acestora se găsesc în interiorul aceleiași entități, numită **clasa**. Evident, în codul din exemplu sunt folosite concepte care nu au fost încă explicate, dar cunoașterea și înțelegerea lor reprezintă scopul principal al acestui laborator.</note> | ||
- | === Clase și Obiecte === | + | ==== Clase și Obiecte ==== |
- | == Ce este un obiect? Ce este o clasă? == | + | === Ce este un obiect? Ce este o clasă? === |
* Atunci când un producător crează un produs, mai întâi acesta specifică toate caracteristicile produsului într-un document de specificații, iar pe baza acelui document se crează fizic produsul. De exemplu, calculatorul este un produs creat pe baza unui astfel de document de specificații. La fel stau lucrurile și într-un program orientat pe obiecte: mai întâi se crează **clasa** obiectului (documentul de specificații) care înglobează toate caracteristicile unui **obiect** (instanță a clasei), dupa care, pe baza acesteia, se crează (instanțiază) obiectul în memorie. | * Atunci când un producător crează un produs, mai întâi acesta specifică toate caracteristicile produsului într-un document de specificații, iar pe baza acelui document se crează fizic produsul. De exemplu, calculatorul este un produs creat pe baza unui astfel de document de specificații. La fel stau lucrurile și într-un program orientat pe obiecte: mai întâi se crează **clasa** obiectului (documentul de specificații) care înglobează toate caracteristicile unui **obiect** (instanță a clasei), dupa care, pe baza acesteia, se crează (instanțiază) obiectul în memorie. | ||
Line 68: | Line 64: | ||
</note> | </note> | ||
- | == Definirea unei clase == | + | === Definirea unei clase === |
* Din cele de mai sus deducem că o clasă descrie un obiect, în general, un nou tip de date. Într-o **clasă** găsim **date** și **metode** ce operează asupra datelor respective. | * Din cele de mai sus deducem că o clasă descrie un obiect, în general, un nou tip de date. Într-o **clasă** găsim **date** și **metode** ce operează asupra datelor respective. | ||
* Pentru a defini o clasă, trebuie folosit cuvântul cheie ''class'' urmat de numele clasei. | * Pentru a defini o clasă, trebuie folosit cuvântul cheie ''class'' urmat de numele clasei. | ||
Line 87: | Line 83: | ||
</note> | </note> | ||
- | == Crearea unui obiect == | + | === Crearea unui obiect === |
* Spuneam mai sus că un obiect reprezintă o instanță a unei clasa. În Java, instanțierea sau crearea unui obiect se face dinamic, folosind cuvântul cheie ''new'' și are ca efect crearea efectivă a obiectului cu alocarea spațiului de memorie corespunzător. | * Spuneam mai sus că un obiect reprezintă o instanță a unei clasa. În Java, instanțierea sau crearea unui obiect se face dinamic, folosind cuvântul cheie ''new'' și are ca efect crearea efectivă a obiectului cu alocarea spațiului de memorie corespunzător. | ||
* Așa cum fiecare calculator construit pe baza documentului de specificații are propriile componente, fiecare obiect de tip ''Carte'' are propriile sale atribute. | * Așa cum fiecare calculator construit pe baza documentului de specificații are propriile componente, fiecare obiect de tip ''Carte'' are propriile sale atribute. | ||
Line 119: | Line 115: | ||
Point p; | Point p; | ||
Dimension d; | Dimension d; | ||
- | | + | |
public Rectangle(Point p, Dimension d) { | public Rectangle(Point p, Dimension d) { | ||
this.p = p; | this.p = p; | ||
Line 168: | Line 164: | ||
* Atribuirea ''c3 = c2'' nu a făcut altceva decât să atașeze referinței ''c3'' obiectul având aceeași identitate precum cel referit de ''c2'', adică obiectul secund creat. | * Atribuirea ''c3 = c2'' nu a făcut altceva decât să atașeze referinței ''c3'' obiectul având aceeași identitate precum cel referit de ''c2'', adică obiectul secund creat. | ||
+ | === Trimiterea datelor în Java === | ||
+ | |||
+ | Spre deosebire de C++, în Java nu există o modalitate prin care să poată fi făcută o diferențiere explicită între trimiterea parametrilor **<color red>prin referință</color>** și trimiterea acestora **<color blue>prin valoare</color>**. | ||
+ | |||
+ | Conform specificației Java ([[https://docs.oracle.com/javase/specs/jls/se9/html/jls-4.html#jls-4.3|secțiunea 4.3]]), transmiterea tuturor datelor, atât a celor de tip obiect, cât și a celor primitive, este definită următoarea regulă:. | ||
+ | |||
+ | <note important>In Java argumentele sunt trimise doar **<color blue>prin valoare</color>** (pass-by-value).</note> | ||
+ | |||
+ | Chiar dacă la o primă vedere această regulă poate să pară simplă, este necesară o explicație suplimentară. În cazul valorilor primitive, valoarea este considerată pur și simplu data asociată (exemple ''1'', ''10.5'', ''true'') iar valoarea parametrilor este copiată de fiecare dată când ei sunt plasați în apeluri. | ||
+ | |||
+ | În ceea ce privește obiectele, în Java, se utilizează următoarea regulă, mai extinsă: | ||
+ | |||
+ | <note important>Valoarea asociată unui obiecte este, de fapt, un pointer, numit referință, la obiectul din memorie.</note> | ||
+ | |||
+ | Spre exemplu, dacă definim o expresie de forma ''Foo foo = new Foo();'', variabila ''foo'' nu deține obiectul ''Foo'' creat, ci, mai degrabă, o valoare a pointerului pentru obiectul ''Foo'' creat. Valoarea acestui pointer la obiect (ceea ce în specificația Java se numește **o referință de obiect** sau pur și simplu **referință**) este copiată de fiecare dată când obiectul este plasat ca argument al unui apel. | ||
+ | |||
+ | În Java, numai următoarele operații pot fi efectuate pe o referință de obiect: | ||
+ | * accesarea câmurilor; | ||
+ | * invocarea metodelor; | ||
+ | * operatorul pentru castare; | ||
+ | * operatorul pentru concatenarea string-urilor (atunci când primește ca parametru o referință la un obiect, o să realizeze o conversie a referinței la String, prin invocarea metodei ''toString'' pentru obiectul referențiat); | ||
+ | * operatorul ''instanceof''; | ||
+ | * operatorii de egalitate pentru referințe: ''=='' și ''!=''; | ||
+ | * operatorul condițional: ''? :''. | ||
+ | |||
+ | <note tip>În practică, acest lucru înseamnă că putem schimba câmpurile obiectului trimis ca parametru într-o metodă și să invocăm metodele acestuia, însă nu putem schimba obiectul spre care pointează referința. Deoarece referința este plasată prin valoare, pointerul original este copiat în stiva de apeluri atunci când metoda este invocată.</note> | ||
+ | |||
+ | {{ :poo:breviare:java-pass-by-value.png |}} | ||
+ | |||
+ | Pentru a înțelege mai bine conceptele prezentate în această secțiune, puteți consulta și analiza rezultatele pentru următoarele secvențe de cod. | ||
+ | |||
+ | <code java> | ||
+ | int someValue = 10; | ||
+ | int anotherValue = someValue; | ||
+ | someValue = 17; | ||
+ | System.out.println("Some value = " + someValue); | ||
+ | System.out.println("Another value = " + anotherValue); | ||
+ | </code> | ||
+ | |||
+ | <code java> | ||
+ | public class Test { | ||
+ | public void process(int value) { | ||
+ | System.out.println("Entered method (value = " + value + ")"); | ||
+ | value = 50; | ||
+ | System.out.println("Changed value within method (value = " + value + ")"); | ||
+ | System.out.println("Leaving method (value = " + value + ")"); | ||
+ | } | ||
+ | |||
+ | public static void main(String args[]) { | ||
+ | Test processor = new Test(); | ||
+ | int someValue = 7; | ||
+ | System.out.println("Before calling method (value = " + someValue + ")"); | ||
+ | processor.process(someValue); | ||
+ | System.out.println("After calling method (value = " + someValue + ")"); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <code java> | ||
+ | class Ball {} | ||
+ | |||
+ | class Main { | ||
+ | public static void main(String args[]) { | ||
+ | Ball someBall = new Ball(); | ||
+ | System.out.println("Some ball before creating another ball = " + someBall); | ||
+ | Ball anotherBall = someBall; | ||
+ | someBall = new Ball(); | ||
+ | System.out.println("Some ball = " + someBall); | ||
+ | System.out.println("Another ball = " + anotherBall); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <code java> | ||
+ | class Vehicle { | ||
+ | private String name; | ||
+ | public Vehicle(String name) { | ||
+ | this.name = name; | ||
+ | } | ||
+ | public void setName(String name) { | ||
+ | this.name = name; | ||
+ | } | ||
+ | public String getName() { | ||
+ | return name; | ||
+ | } | ||
+ | @Override | ||
+ | public String toString() { | ||
+ | return "Vehicle[name = " + name + "]"; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class VehicleProcessor { | ||
+ | public void process(Vehicle vehicle) { | ||
+ | System.out.println("Entered method (vehicle = " + vehicle + ")"); | ||
+ | vehicle.setName("A changed name"); | ||
+ | System.out.println("Changed vehicle within method (vehicle = " + vehicle + ")"); | ||
+ | System.out.println("Leaving method (vehicle = " + vehicle + ")"); | ||
+ | } | ||
+ | public void processWithReferenceChange(Vehicle vehicle) { | ||
+ | System.out.println("Entered method (vehicle = " + vehicle + ")"); | ||
+ | vehicle = new Vehicle("A new name"); | ||
+ | System.out.println("New vehicle within method (vehicle = " + vehicle + ")"); | ||
+ | System.out.println("Leaving method (vehicle = " + vehicle + ")"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class Main { | ||
+ | public static void main(String args[]) { | ||
+ | VehicleProcessor processor = new VehicleProcessor(); | ||
+ | Vehicle vehicle = new Vehicle("Some name"); | ||
+ | System.out.println("Before calling method (vehicle = " + vehicle + ")"); | ||
+ | processor.process(vehicle); | ||
+ | System.out.println("After calling method (vehicle = " + vehicle + ")"); | ||
+ | processor.processWithReferenceChange(vehicle); | ||
+ | System.out.println("After calling reference-change method (vehicle = " + vehicle + ")"); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
=== Componența unei clase === | === Componența unei clase === | ||
Line 183: | Line 297: | ||
Dacă programatorul nu prevede într-o clasa niciun constructor, atunci compilatorul va genera pentru clasa respectivă un constructor implicit fără niciun argument și al cărui corp de instrucțiuni este vid. | Dacă programatorul nu prevede într-o clasa niciun constructor, atunci compilatorul va genera pentru clasa respectivă un constructor implicit fără niciun argument și al cărui corp de instrucțiuni este vid. | ||
</note> | </note> | ||
+ | |||
+ | {{ :poo:breviare:default-constructor1.png |}} | ||
<note warning> | <note warning> | ||
Line 225: | Line 341: | ||
<note warning> | <note warning> | ||
- | * Un membru static al unei clase caracterizează clasa în interiorul căreia este definit precum și toate obiectele clasei respective. | + | Un membru static al unei clase caracterizează clasa în interiorul căreia este definit precum și toate obiectele clasei respective. |
- | * Un membru al unei clase (atribut sau metodă) este static dacă el este precedat de cuvântul cheie ''static''. | + | |
- | * Din interiorul unei metode statice pot fi accesați doar alți membri statici ai clasei în care este definită metoda, accesarea membrilor nestatici ai clasei producând o eroare de compilare. | + | Un membru al unei clase (atribut sau metodă) este static dacă el este precedat de cuvântul cheie ''static''. |
- | * Trebuie avut în vedere contextul static al metodei **main**. Dintr-un context static nu se pot apela funcții nestatice, în schimb, se pot crea obiecte ale oricărei clase. | + | |
+ | Din interiorul unei metode statice pot fi accesați doar alți membri statici ai clasei în care este definită metoda, accesarea membrilor nestatici ai clasei producând o eroare de compilare. | ||
+ | |||
+ | Trebuie avut în vedere contextul static al metodei **main**. Dintr-un context static nu se pot apela funcții nestatice, în schimb, se pot crea obiecte ale oricărei clase. | ||
</note> | </note> | ||
- | === Principii POO === | + | ==== Principii POO ==== |
<note important> | <note important> | ||
Mai multe funcții pot avea același nume în același domeniu de definiție, dacă se pot diferenția prin numărul sau tipul argumentelor de apel. | Mai multe funcții pot avea același nume în același domeniu de definiție, dacă se pot diferenția prin numărul sau tipul argumentelor de apel. | ||
</note> | </note> | ||
- | == Supraincarcarea == | + | === Supraîncarcarea === |
În Java, se pot găsi două sau mai multe metode, în cadrul aceleiași clase, care să aibă același nume, atâta timp cât argumentele lor sunt diferite. În acest caz, se spune că metoda este supraîncărcată, iar procedeul se numește **supraîncarcarea metodelor**. | În Java, se pot găsi două sau mai multe metode, în cadrul aceleiași clase, care să aibă același nume, atâta timp cât argumentele lor sunt diferite. În acest caz, se spune că metoda este supraîncărcată, iar procedeul se numește **supraîncarcarea metodelor**. | ||
Pentru o mai bună înțelegere a acestui principiu POO, se va oferi, în continuare, un exemplu pentru o metodă care determină maximul. | Pentru o mai bună înțelegere a acestui principiu POO, se va oferi, în continuare, un exemplu pentru o metodă care determină maximul. |