Clasa si Obiect, Concepte de Baza
Cuprins
- Clasa și Obiect
- Constructori
- Atribute
- Metode
- Convenții Java
- Cuvinte Cheie
- Compararea Obiectelor
- Specificatori de Acces
- Garbage Collector
Clasa și Obiect
Clasa
Clasa este un șablon sau o structură care definește:
- Atributele (variabilele)
- Comportamentul (metodele)
Clasa reprezintă conceptul abstract al unui tip de obiect, definind structura și comportamentul obiectelor care vor fi create bazate pe această clasă.
public class Student {
// Atribute
private String nume;
private int varsta;
// Constructor
public Student(String nume, int varsta) {
this.nume = nume;
this.varsta = varsta;
}
// Metode
public void studiere() {
System.out.println(nume + " studiază");
}
}
Obiect
Obiectul este o instanță a unei clase. Reprezintă implementarea concretă a unui șablon definit de clasă.
// Crearea unui obiect de tip Student
Student student1 = new Student("Ion", 20);
Student student2 = new Student("Maria", 21);
// Apelarea metodelor obiectului
student1.studiere(); // Output: Ion studiază
student2.studiere(); // Output: Maria studiază
Constructori
Constructorii sunt metode speciale care sunt apelate automat la crearea unui obiect și sunt folosite pentru:
- Inițializarea atributelor
- Alocarea resurselor necesare
Caracteristici:
- Au același nume ca și clasa
- Nu au tip de retur, nici măcar
void
- Pot fi supraîncărcați (overloaded)
public class Carte {
private String titlu;
private String autor;
private int anPublicatie;
// Constructor implicit
public Carte() {
titlu = "Necunoscut";
autor = "Anonim";
anPublicatie = 2000;
}
// Constructor cu parametri
public Carte(String titlu, String autor) {
this.titlu = titlu;
this.autor = autor;
this.anPublicatie = 2000; // valoare implicită
}
// Constructor cu toți parametrii
public Carte(String titlu, String autor, int anPublicatie) {
this.titlu = titlu;
this.autor = autor;
this.anPublicatie = anPublicatie;
}
}
Atribute
Atributele sunt variabilele definite într-o clasă, reprezentând starea sau datele unui obiect.
public class Persoana {
// Atribute
private String nume; // atribut de instanță
private String prenume; // atribut de instanță
private int varsta; // atribut de instanță
private static int numarPersoane; // atribut static (de clasă)
private final String CNP; // atribut constant (final)
// Constructor
public Persoana(String nume, String prenume, int varsta, String CNP) {
this.nume = nume;
this.prenume = prenume;
this.varsta = varsta;
this.CNP = CNP;
numarPersoane++;
}
}
Clasificarea atributelor:
- Atribute de instanță: aparțin fiecărui obiect și pot avea valori diferite pentru fiecare instanță
- Atribute statice (de clasă): aparțin clasei, nu instanțelor; sunt comune pentru toate obiectele de acel tip
- Atribute finale (constante): nu pot fi modificate după inițializare
Metode
Metodele definesc comportamentul unui obiect și reprezintă acțiunile pe care obiectul le poate executa.
public class Calculator {
// Atribute
private double rezultat;
// Metode
public void aduna(double a, double b) {
rezultat = a + b;
}
public void scade(double a, double b) {
rezultat = a - b;
}
public double getRezultat() {
return rezultat;
}
// Metodă statică
public static double patrat(double numar) {
return numar * numar;
}
}
Clasificarea metodelor:
- Metode de instanță: aparțin fiecărui obiect și pot accesa atributele și alte metode ale instanței
- Metode statice (de clasă): aparțin clasei, nu instanțelor; nu pot accesa atributele non-statice sau metodele de instanță
- Metode finale: nu pot fi suprascrise în subclase
Convenții Java
Convenții de numire
Java folosește următoarele convenții de numire:
- Clase:
- Substantive
- CamelCase cu prima literă mare (PascalCase)
- Exemple:
Student
,ContBancar
,GestiuneAngajati
- Atribute și Metode:
- Verbe pentru metode (acțiuni)
- camelCase cu prima literă mică
- Exemple:
nume
,adresaEmail
,calculeazaSalariu()
- Constante:
- Toate literele majuscule, cu subliniere între cuvinte
- Exemple:
MAX_SIZE
,PI
,DATABASE_URL
- Pachete:
- Toate literele mici
- De obicei folosește domeniul inversat (ex:
org.example.proiect
) - Exemple:
java.util
,com.companie.proiect
Bune practici
- Numele ar trebui să fie descriptive și să indice scopul
- Evitați abrevierile ambigue
- Folosiți pluralul pentru colecții (ex:
List<Student> studenti
) - Utilizați prefixe pentru variabile boolean:
is
,has
,can
(ex:isActive
,hasChildren
)
Cuvinte Cheie
new
Cuvântul cheie new
este utilizat pentru a instanția un obiect (a crea o instanță a unei clase).
// Sintaxă: TipClasa numeVariabila = new TipClasa(parametri);
String text = new String("Hello World");
ArrayList<Integer> numere = new ArrayList<>();
Student student = new Student("Ana", 22);
Procesul când se folosește new
:
- Se alocă memorie pentru noul obiect
- Se apelează constructorul clasei
- Se returnează o referință către obiectul nou creat
null
null
reprezintă o valoare specială care indică faptul că o variabilă de tip referință nu referă niciun obiect.
// Declararea unei variabile fără a o inițializa
Student student; // valoarea implicită este null
// Atribuirea explicită a valorii null
String mesaj = null;
// Verificarea pentru null
if (mesaj == null) {
System.out.println("Mesajul este null!");
}
Pericole:
- Apelarea metodelor pe o referință
null
genereazăNullPointerException
- Este considerată o bună practică verificarea valorilor pentru
null
înainte de a le utiliza
this
Cuvântul cheie this
se referă la obiectul curent (instanța curentă a clasei).
Utilizări:
- Rezolvarea ambiguității între atributele clasei și parametrii metodei/constructorului:
public class Persoana {
private String nume;
public Persoana(String nume) {
this.nume = nume; // this.nume se referă la atributul clasei
}
}
- Apelarea unui alt constructor din același clasă:
public class Persoana {
private String nume;
private int varsta;
public Persoana() {
this("Necunoscut", 0); // Apelează celălalt constructor
}
public Persoana(String nume, int varsta) {
this.nume = nume;
this.varsta = varsta;
}
}
- Pentru returnarea obiectului curent (permite înlănțuirea metodelor):
public class Builder {
private int valoare;
public Builder adauga(int x) {
valoare += x;
return this; // Returnează obiectul curent
}
public Builder scade(int x) {
valoare -= x;
return this;
}
}
// Utilizare:
Builder b = new Builder();
b.adauga(5).scade(2).adauga(10); // Înlănțuire de metode
static
Cuvântul cheie static
este folosit pentru a declara membri (atribute sau metode) care aparțin clasei înseși, nu instanțelor individuale.
Atribute statice:
- Sunt comune tuturor instanțelor clasei
- Sunt inițializate o singură dată, la încărcarea clasei
- Pot fi accesate direct prin numele clasei
public class Contor {
private static int numar = 0; // atribut static
public Contor() {
numar++; // incrementat la fiecare instanțiere
}
public static int getNumar() { // metodă statică
return numar;
}
}
// Utilizare:
Contor c1 = new Contor();
Contor c2 = new Contor();
System.out.println(Contor.getNumar()); // Output: 2
Metode statice:
- Nu pot accesa atribute non-statice sau metode non-statice direct
- Nu pot utiliza cuvântul cheie
this
- Pot fi apelate direct prin numele clasei fără a crea o instanță
- Exemple comune:
Math.sqrt()
,Arrays.sort()
,Collections.sort()
final
Cuvântul cheie final
poate fi aplicat variabilelor, metodelor și claselor pentru a impune restricții.
- Variabile finale (constante):
- Nu pot fi modificate după inițializare
- Trebuie inițializate la declarare sau în constructor
public class Constante {
final int MAX_UTILIZATORI = 100; // inițializat la declarare
final String PREFIX;
public Constante(String prefix) {
this.PREFIX = prefix; // inițializat în constructor
}
}
- Metode finale:
- Nu pot fi suprascrise în subclase
public class Parinte {
public final void metodaFinala() {
// implementare care nu poate fi modificată în subclase
}
}
- Clase finale:
- Nu pot fi extinse (nu pot avea subclase)
- Exemple:
String
,Integer
,Math
public final class ClasaFinala {
// Această clasă nu poate fi extinsă
}
Supraîncărcarea Metodelor
Supraîncărcarea metodelor (method overloading) este abilitatea de a defini mai multe metode cu același nume dar cu parametri diferiți în aceeași clasă.
Criteriile pentru supraîncărcarea metodelor:
- Trebuie să difere prin numărul parametrilor și/sau
- Trebuie să difere prin tipul parametrilor
Tipul de retur NU este luat în considerare pentru determinarea supraîncărcării.
public class Calculator {
// Supraîncărcarea metodei de adunare
// Versiunea pentru două numere întregi
public int aduna(int a, int b) {
return a + b;
}
// Versiunea pentru trei numere întregi
public int aduna(int a, int b, int c) {
return a + b + c;
}
// Versiunea pentru două numere reale
public double aduna(double a, double b) {
return a + b;
}
// Versiunea pentru un număr întreg și unul real
public double aduna(int a, double b) {
return a + b;
}
}
Avantajele supraîncărcării metodelor:
- Îmbunătățește lizibilitatea și reutilizarea codului
- Permite utilizarea aceluiași nume pentru operații similare
- Metodele pot fi apelate cu tipuri diferite de parametri
Compararea Obiectelor
În Java, există două metode principale pentru a compara obiecte:
- Operatorul
==
compară referințele (dacă două variabile referă același obiect) - Metoda
equals()
compară conținutul obiectelor (valorile)
Metoda equals()
Semnătură: public boolean equals(Object obj)
- Este moștenită din clasa
Object
- Implementarea implicită compară referințele (identic cu
==
) - Pentru compararea corectă a conținutului, trebuie suprascrisă
public class Persoana {
private String nume;
private String CNP;
public Persoana(String nume, String CNP) {
this.nume = nume;
this.CNP = CNP;
}
// Getteri și setteri
// Suprascriere metoda equals
@Override
public boolean equals(Object obj) {
// Verificare dacă obiectul este aceeași instanță
if (this == obj) {
return true;
}
// Verificare dacă obiectul este null sau de alt tip
if (obj == null || getClass() != obj.getClass()) {
return false;
}
// Conversie la tipul corect
Persoana altaPersoana = (Persoana) obj;
// Compararea atributelor relevante
return CNP != null && CNP.equals(altaPersoana.CNP);
}
// De obicei, hashCode() este suprascrisa împreună cu equals()
@Override
public int hashCode() {
return CNP != null ? CNP.hashCode() : 0;
}
}
Reguli pentru implementarea corectă a metodei equals()
:
- Reflexivitate: Pentru orice obiect
x
,x.equals(x)
trebuie să returnezetrue
- Simetrie: Pentru orice obiect
x
șiy
, dacăx.equals(y)
returneazătrue
, atunciy.equals(x)
trebuie să returnezetrue
- Tranzitivitate: Pentru orice obiecte
x
,y
șiz
, dacăx.equals(y)
șiy.equals(z)
returneazătrue
, atuncix.equals(z)
trebuie să returnezetrue
- Consistență: Pentru orice obiecte
x
șiy
, apeluri multiple alex.equals(y)
trebuie să returneze constanttrue
saufalse
, presupunând că nu s-a modificat nicio informație - Pentru orice obiect non-null
x
,x.equals(null)
trebuie să returnezefalse
Notă: Când suprascriezi equals()
, ar trebui să suprascrii și hashCode()
pentru a menține contractul hashCode-equals.
Specificatori de Acces
Specificatorii de acces controlează vizibilitatea (accesibilitatea) claselor, atributelor, metodelor și constructorilor.
Specificator | Clasa | Pachet | Subclase | Global |
---|---|---|---|---|
public |
Da | Da | Da | Da |
protected |
Da | Da | Da | Nu |
default | Da | Da | Nu | Nu |
private |
Da | Nu | Nu | Nu |
public
- Accesibil din orice loc
- Utilizat pentru interfețe publice și clase care vor fi folosite de alte pachete
public class ContBancar {
public void depunere(double suma) {
// Metodă accesibilă din orice loc
}
}
protected
- Accesibil în același pachet și în subclase (chiar dacă subclasele sunt în alte pachete)
- Permite subclaselor să acceseze și să suprascrie membri
public class Animal {
protected void respira() {
// Accesibil în același pachet și în subclase
}
}
default (fără specificator)
- Accesibil doar în același pachet
- Se numește și “package-private”
class Helper {
void ajuta() {
// Accesibil doar în același pachet
}
}
private
- Accesibil doar în interiorul clasei
- Cel mai restrictiv nivel de acces
- Utilizat pentru detalii de implementare
public class Utilizator {
private String parola;
private void schimbaParola(String parolaNoua) {
// Accesibil doar în interiorul clasei
this.parola = parolaNoua;
}
}
Garbage Collector
Garbage Collector (GC) este un proces automat în Java care:
- Identifică și elimină obiectele care nu mai sunt referite (inaccesibile)
- Eliberează memoria ocupată de acestea
- Rulează automat, fără intervenția programatorului
Cum funcționează Garbage Collector
- Identifică obiectele care nu mai sunt referite de nicio variabilă accesibilă
- Apelează metoda
finalize()
(dacă este suprascrisă) înainte de ștergerea obiectului - Eliberează memoria ocupată de obiect
Demonstrarea Garbage Collector-ului
public class DemoGC {
private String nume;
public DemoGC(String nume) {
this.nume = nume;
System.out.println("Obiect creat: " + nume);
}
@Override
protected void finalize() {
System.out.println("Obiect eliminat: " + nume);
}
public static void main(String[] args) {
// Crearea obiectelor
DemoGC obj1 = new DemoGC("Obiect 1");
DemoGC obj2 = new DemoGC("Obiect 2");
// Eliminarea referințelor
obj1 = null; // Obiect 1 devine eligibil pentru GC
// Sugeram Garbage Collector să ruleze
System.gc();
// Așteptăm puțin pentru a vedea efectele
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Program terminat");
}
}
Notă: Apelarea System.gc()
doar sugerează JVM să ruleze GC, dar nu garantează că va rula imediat sau că va colecta toate obiectele nereferenciate.
Exemple
Pentru a testa o parte din conceptele de mai sus incarcati in IDE urmatorul proiect Java: exemple-curs-2-oop