This shows you the differences between two versions of the page.
poo-ca-cd:laboratoare:design-avansat-de-clase [2025/10/13 22:00] florian_luis.micu [Accesarea variabilelor și metodelor unui obiect] |
poo-ca-cd:laboratoare:design-avansat-de-clase [2025/10/13 22:40] (current) florian_luis.micu [Laboratorul 2: Obiecte în Java] |
||
---|---|---|---|
Line 3: | Line 3: | ||
* Autori: [[miculuis1@gmail.com | Florian-Luis Micu ]], [[sorinabuf@gmail.com | Sorina-Anamaria Buf ]], [[stefancocioran@gmail.com | Ștefan Cocioran ]] | * Autori: [[miculuis1@gmail.com | Florian-Luis Micu ]], [[sorinabuf@gmail.com | Sorina-Anamaria Buf ]], [[stefancocioran@gmail.com | Ștefan Cocioran ]] | ||
* Data publicării: 13.10.2025 | * Data publicării: 13.10.2025 | ||
- | * Data ultimei modificări: 13.10.2025 | + | * Data ultimei modificări: 14.10.2025 |
+ | * reordonarea secțiunilor, mutarea anumitor concepte în [Nice to know] și refrazări. | ||
===== Obiective ===== | ===== Obiective ===== | ||
Line 233: | Line 234: | ||
<note important> | <note important> | ||
- | * În Java, câmpurile **neinițializate** primesc valoarea implicită 0 sau echivalentul acestei valori pentru tipul de date respectiv (ex. ''bool'' -> ''false'', ''float'' -> ''0.f''). Din acest motiv, variabila membru ''mass'' are valoarea ''0''. | + | În Java, câmpurile **neinițializate** primesc valoarea implicită 0 sau echivalentul acestei valori pentru tipul de date respectiv (ex. ''bool'' -> ''false'', ''float'' -> ''0.f'', ''Apple'' -> ''null''). Din acest motiv, variabila membru ''mass'' are valoarea ''0''. Țineți cont că acestă inițializare default se întâmplă **doar pentru câmpuri** și **nu pentru variabilele locale** dintr-o metodă. |
- | * Metoda "main" poate fi introdusă în **orice** clasă, puteți avea chiar mai multe metode "main" în mai multe clase, dar doar o **singură** metodă "main" poate fi pornită la un anumit moment de timp. | + | </note> |
+ | |||
+ | <note tip> | ||
+ | Metoda "main" poate fi introdusă în **orice** clasă, puteți avea chiar mai multe metode "main" în mai multe clase, dar doar o **singură** metodă "main" poate fi pornită la un anumit moment de timp. | ||
</note> | </note> | ||
Line 253: | Line 257: | ||
===Variabile locale=== | ===Variabile locale=== | ||
- | O variabilă locală este: | + | O variabilă locală: |
- | * creată la apelul metodei; | + | * este creată la apelul metodei; |
- | * ștearsă automat când metoda se termină; | + | * este ștearsă automat când metoda se termină; |
* trebuie inițializată înainte de a fi folosită. | * trebuie inițializată înainte de a fi folosită. | ||
Line 267: | Line 271: | ||
<note important> | <note important> | ||
- | Spre deosebire de variabilele instanței, variabilele locale **nu primesc valori implicite**. Dacă se încearcă folosirea unei variabile locale fără inițializare, se va afișa o **eroare de compilare**. | + | Spre deosebire de variabilele instanței (câmpuri), variabilele locale **nu primesc valori implicite**. Dacă se încearcă folosirea unei variabile locale fără inițializare, se va afișa o **eroare de compilare**. |
</note> | </note> | ||
===Inițializarea variabilelor locale=== | ===Inițializarea variabilelor locale=== | ||
- | Java **nu permite** folosirea unei variabile locale fără inițializare sigură. | + | Java **nu permite** folosirea unei variabile locale fără **inițializare sigură**. |
Un exemplu de cod greșit este următorul: | Un exemplu de cod greșit este următorul: | ||
Line 292: | Line 296: | ||
<code java> | <code java> | ||
class Apple { | class Apple { | ||
- | int x, y; | + | int x = 2; |
+ | int y = 3; | ||
+ | // Presupunem că argumentele pasate sunt: x = 10, y = 11 | ||
void moveTo(int x, int y) { | void moveTo(int x, int y) { | ||
- | System.out.println("Moving apple to " + x + ", " + y); | + | System.out.println("Moving apple to (" + x + ", " + y + ")"); |
} | } | ||
} | } | ||
</code> | </code> | ||
- | În acest exemplu, ''x'' și ''y'' din metodă sunt **parametrii**, nu variabilele ale instanței. | + | <spoiler Output> |
- | Pentru a accesa variabilele care aparțin instaței, trebuie să folosim keyword-ul ''this'', prezentat mai jos. | + | <code bash> |
+ | Moving apple to (10, 11) | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | În acest exemplu, ''x'' și ''y'' din metodă sunt **parametrii** metodei, nu variabilele ale instanței. | ||
+ | |||
+ | Pentru a accesa variabilele care aparțin instanței, trebuie să folosim keyword-ul ''this'', prezentat mai jos. | ||
===Supraîncărcarea metodelor=== | ===Supraîncărcarea metodelor=== | ||
Line 341: | Line 354: | ||
Un alt exemplu cu care sunteți deja familiari este chiar metoda ''print()'' în care puteți introduce mai multe tipuri de argumente. | Un alt exemplu cu care sunteți deja familiari este chiar metoda ''print()'' în care puteți introduce mai multe tipuri de argumente. | ||
- | |||
- | <code java> | ||
- | class PrintStream { | ||
- | void print(char[] arg) { ... } | ||
- | void print(int arg) { ... } | ||
- | void print(double arg) { ... } | ||
- | // etc. | ||
- | } | ||
- | </code> | ||
<code java> | <code java> | ||
Line 357: | Line 361: | ||
</code> | </code> | ||
- | ==Cum alege compilatorul metoda corectă?== | + | <spoiler [Nice to know] Detalii despre algoritmul din spatele supraîncărcării> |
Compilatorul Java folosește următorul algoritm pentru supraîncărcare: | Compilatorul Java folosește următorul algoritm pentru supraîncărcare: | ||
- Caută o potrivire exactă a tipurilor de argumente. | - Caută o potrivire exactă a tipurilor de argumente. | ||
Line 368: | Line 371: | ||
* Vom detalia moștenirea în laboratorul următor. | * Vom detalia moștenirea în laboratorul următor. | ||
</note> | </note> | ||
+ | </spoiler> | ||
====Crearea obiectelor==== | ====Crearea obiectelor==== | ||
Line 393: | Line 397: | ||
int day = 1; | int day = 1; | ||
+ | // Constructor explicit adăugat de programator | ||
SpecialDate(int day) { | SpecialDate(int day) { | ||
this.day = day; | this.day = day; | ||
Line 411: | Line 416: | ||
SpecialDate date2 = new SpecialDate(30); | SpecialDate date2 = new SpecialDate(30); | ||
</code> | </code> | ||
+ | </note> | ||
+ | |||
+ | <note tip> | ||
+ | Constructorii **nu au tip de return** pentru că returnează tipul clasei automat pentru instanțiere. | ||
</note> | </note> | ||
===Supraincărcarea constructorilor=== | ===Supraincărcarea constructorilor=== | ||
- | Java permite existența mai multor constructori în aceeași clasă, cu semnături diferite. Alegerea constructorului potrivit se face la compilare, conform regulilor de selecție a metodelor supraincărcate. | + | Java permite existența **mai multor constructori** în aceeași clasă, cu **semnături diferite**. Alegerea constructorului potrivit se face la compilare, conform regulilor de selecție a metodelor supraincărcate. |
<code java> | <code java> | ||
Line 432: | Line 441: | ||
} | } | ||
</code> | </code> | ||
+ | |||
+ | <note tip> | ||
+ | * Puteți crea oricâți constructori doriți într-o clasă. | ||
+ | * Din punct de vedere al coding style-ului vă recomandăm să ordonați constructorii după numărul de parametrii. | ||
+ | </note> | ||
===Copy constructor=== | ===Copy constructor=== | ||
- | În Java, există conceptul de **copy constructor**, acesta reprezentând un constructor care ia ca parametru un obiect de același tip cu clasa în care se află constructorul respectiv. Cu ajutorul acestui constructor, putem să copiem obiecte, prin copierea membru cu membru în constructor. | + | În Java, există conceptul de **copy constructor**, acesta reprezentând un constructor care ia ca parametru un obiect de același tip cu clasa în care se află constructorul respectiv. Cu ajutorul acestui constructor, putem să **copiem obiecte**, prin copierea membru cu membru în constructor. |
<code java> | <code java> | ||
Line 449: | Line 463: | ||
// copy constructor | // copy constructor | ||
public Student(Student student) { | public Student(Student student) { | ||
- | // name este camp privat, noi il putem accesa direct (student.name) | + | /* |
- | // deoarece ne aflam in interiorul clasei | + | "name" este câmp privat, noi îl putem accesa direct (student.name) |
+ | deoarece ne aflam in interiorul clasei | ||
+ | */ | ||
this.name = student.name; | this.name = student.name; | ||
this.averageGrade = student.averageGrade; | this.averageGrade = student.averageGrade; | ||
Line 493: | Line 509: | ||
===Garbage Collection=== | ===Garbage Collection=== | ||
- | Mecanismul de garbage collection are rolul de a **elibera memoria** ocupată de obiectele care nu mai sunt accesibile. Un obiect devine neaccesibil atunci când nu mai există **nicio referință activă** către el. | + | Mecanismul de garbage collection are rolul de a **elibera memoria** ocupată de obiectele care nu mai sunt accesibile. Un obiect devine inaccesibil atunci când nu mai există **nicio referință activă** către el. |
<code java> | <code java> | ||
Line 562: | Line 578: | ||
''this'' se folosește pentru: | ''this'' se folosește pentru: | ||
- | 1. **Dezambiguizare**, prin accesarea la variabile care aparțin instanței ce sunt ascunse de parametri: | + | 1. **Dezambiguizare**, prin accesarea variabilelor care aparțin instanței ce sunt ascunse de parametri: |
<code java> | <code java> | ||
Line 622: | Line 638: | ||
</note> | </note> | ||
- | 3. **Apelul către un alt constructor din aceeași clasă:** | + | 3. Apelul către un **alt constructor** din aceeași clasă: |
- | Keyword-ul ''this'' are un al treilea scenariu în care poate fi folosit, concret apelul către un alt constructor din aceeași clasă se face cu ''this(...)'' și trebuie să fie **prima instrucțiune** din constructorul curent.<code java> | + | Apelul către un alt constructor din aceeași clasă se face cu ''this(...)'' și trebuie să fie **prima instrucțiune** din constructorul curent.<code java> |
class Car { | class Car { | ||
String model; | String model; | ||
Line 638: | Line 654: | ||
System.out.println("Is this the batmobile?"); | System.out.println("Is this the batmobile?"); | ||
} | } | ||
- | this(model, 4); // eroare, apelul "this" nu se află pe prima linie din constructor | + | this("Batmobile", doors); // eroare, apelul "this" nu se află pe prima linie din constructor |
+ | } | ||
+ | |||
+ | Car(String model) { | ||
+ | this(model, 4); // corect | ||
} | } | ||
} | } | ||
Line 644: | Line 664: | ||
<note tip> | <note tip> | ||
- | Java 25 permite ca apelul ''this()'' să nu se afle pe prima linie din constructor. | + | * Java 25 permite ca apelul ''this()'' să nu se afle pe prima linie din constructor. |
+ | * Recomandăm refolosirea constructorilor pentru a evita **cod duplicat**. | ||
</note> | </note> | ||
Line 738: | Line 759: | ||
<code java> | <code java> | ||
class PropertiesExample { | class PropertiesExample { | ||
- | String myString; | + | private String myString; |
- | String getMyString() { | + | public String getMyString() { |
return myString; | return myString; | ||
} | } | ||
- | void setMyString(String myString) { | + | public void setMyString(String myString) { |
this.myString = myString; | this.myString = myString; | ||
} | } | ||
Line 755: | Line 776: | ||
PropertiesExample pe = new PropertiesExample(); | PropertiesExample pe = new PropertiesExample(); | ||
- | pe.setMyString("This is my string!"); | + | pe.myString = "This is bad"; // nu funcționează pentru că este "private" |
+ | |||
+ | pe.setMyString("This is my string!"); // funcționează | ||
System.out.println(pe.getMyString()); | System.out.println(pe.getMyString()); | ||
Line 911: | Line 934: | ||
==== Alocarea memoriei în Heap ==== | ==== Alocarea memoriei în Heap ==== | ||
- | Obiectele în Java sunt stocate în **heap**, o zonă de memorie dedicată alocărilor dinamice. | + | Obiectele în Java sunt stocate în **Heap**, o zonă de memorie dedicată alocărilor dinamice. Pentru a crea un obiect, folosim operatorul ''new''. |
- | Pentru a crea un obiect, folosim operatorul ''new'', care: | + | |
- | + | ||
- | * alocă spațiu în memoria heap; | + | |
- | * apelează constructorul clasei; | + | |
- | * returnează o **referință** către noul obiect, care este stocată pe stack. | + | |
<code java Student.java> | <code java Student.java> | ||
Line 945: | Line 963: | ||
În exemplul de mai sus: | În exemplul de mai sus: | ||
- | * referința ''st'' este pe **stack**; | + | * referința ''st'' este pe **Stack**; |
- | * obiectul ''Student'' este alocat pe **heap**; | + | * obiectul ''Student'' este alocat pe **Heap**; |
* adresa obiectului din heap este copiată în referința ''st''. | * adresa obiectului din heap este copiată în referința ''st''. | ||
{{:poo-ca-cd:laboratoare:obiecte-in-java:stack_and_heap_vars.png?nolink&750|}} | {{:poo-ca-cd:laboratoare:obiecte-in-java:stack_and_heap_vars.png?nolink&750|}} | ||
- | Când metoda în care a fost creat obiectul se termină, referința ''st'' dispare, dar obiectul rămâne în heap până când **Garbage Collector-ul** decide că nu mai este utilizat. | + | Când metoda în care a fost creat obiectul se termină, referința ''st'' dispare, dar obiectul rămâne în Heap până când **Garbage Collector-ul** decide că nu mai este utilizat (când numărul de referințe către acea zonă din Heap ajunge la 0). |
- | + | ||
- | <note tip> | + | |
- | Heap-ul este gestionat **automat** de JVM prin Garbage Collector, programatorul nu trebuie să elibereze manual memoria. | + | |
- | </note> | + | |
Line 1024: | Line 1038: | ||
</spoiler> | </spoiler> | ||
- | După cum se poate observa, ''a1'' și ''a2'' vor funcționa ca entități independente una de cealaltă, astfel că modificarea câmpului ''mass'' din ''a1'' nu va avea nici un efect implicit și automat în ''a2''. Există totuși situații când dorim să creăm câmpuri care să fie partajate și să nu fie memorate separat pentru fiecare instanță. | + | După cum se poate observa, ''a1'' și ''a2'' vor funcționa ca entități independente una de cealaltă, astfel că modificarea câmpului ''mass'' din ''a1'' nu va avea nici un efect implicit și automat în ''a2''. |
Membrii statici **nu aparțin unei instanțe** anume, ci **clasei** în sine. Aceștia sunt împărtășiți de-a lungul tuturor obiectelor create din acea clasă și pot să fie accesate **fără** să se creeze o instanță, având o locație specială în memorie (diferită de Heap și Stack). | Membrii statici **nu aparțin unei instanțe** anume, ci **clasei** în sine. Aceștia sunt împărtășiți de-a lungul tuturor obiectelor create din acea clasă și pot să fie accesate **fără** să se creeze o instanță, având o locație specială în memorie (diferită de Heap și Stack). | ||
Line 1032: | Line 1046: | ||
Când declarați o variabilă sau o metodă înăuntrul unei clase: | Când declarați o variabilă sau o metodă înăuntrul unei clase: | ||
* **Membrii instanței**: aparțin doar obiectului instanțiat. (ex. ''a1.mass'' și ''a2.mass'' pot avea valori diferite). | * **Membrii instanței**: aparțin doar obiectului instanțiat. (ex. ''a1.mass'' și ''a2.mass'' pot avea valori diferite). | ||
- | * **Membrii statici**: aparțin clasei și sunt împărtășiți de către toate obiectele (ex. toate merele pot avea aceeași constantă gravitațională). | + | * **Membrii statici**: aparțin clasei și sunt împărtășiți de către toate obiectele (ex. toate merele pot avea aceeași constantă gravitațională ''gravAcc''). |
^Tip^Apartenență^Accesat prin^Cum este valoarea reținută în memorie^ | ^Tip^Apartenență^Accesat prin^Cum este valoarea reținută în memorie^ | ||
Line 1073: | Line 1087: | ||
</spoiler> | </spoiler> | ||
- | <note tip> | ||
- | Folosiți variabile statice pentru a avea **configurații împărtășite** sau **constante la nivel de clase**, nu pentru a stoca date per obiect. | ||
- | </note> | ||
====Accesarea membrilor statici==== | ====Accesarea membrilor statici==== | ||
Line 1104: | Line 1115: | ||
public static void main(String[] args) { | public static void main(String[] args) { | ||
float g = Apple.gravAcc; | float g = Apple.gravAcc; | ||
+ | | ||
+ | // Corect, dar nepreferat | ||
+ | Apple a1 = new Apple(); | ||
+ | float g = a1.gravAcc; | ||
} | } | ||
} | } |