Ingineria Sistemelor de Programe

Documentatie suplimentara, ISP, Seria B si SM

View on GitHub

Clasa si Obiect, Concepte de Baza

Cuprins

  1. Clasa și Obiect
  2. Constructori
  3. Atribute
  4. Metode
  5. Convenții Java
  6. Cuvinte Cheie
  7. Compararea Obiectelor
  8. Specificatori de Acces
  9. Garbage Collector

Clasa și Obiect

Clasa

Clasa este un șablon sau o structură care definește:

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:

Caracteristici:

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:

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:

Convenții Java

Convenții de numire

Java folosește următoarele convenții de numire:

  1. Clase:
    • Substantive
    • CamelCase cu prima literă mare (PascalCase)
    • Exemple: Student, ContBancar, GestiuneAngajati
  2. Atribute și Metode:
    • Verbe pentru metode (acțiuni)
    • camelCase cu prima literă mică
    • Exemple: nume, adresaEmail, calculeazaSalariu()
  3. Constante:
    • Toate literele majuscule, cu subliniere între cuvinte
    • Exemple: MAX_SIZE, PI, DATABASE_URL
  4. Pachete:
    • Toate literele mici
    • De obicei folosește domeniul inversat (ex: org.example.proiect)
    • Exemple: java.util, com.companie.proiect

Bune practici

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:

  1. Se alocă memorie pentru noul obiect
  2. Se apelează constructorul clasei
  3. 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:

this

Cuvântul cheie this se referă la obiectul curent (instanța curentă a clasei).

Utilizări:

  1. 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
    }
}
  1. 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;
    }
}
  1. 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:

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:

final

Cuvântul cheie final poate fi aplicat variabilelor, metodelor și claselor pentru a impune restricții.

  1. 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
    }
}
  1. Metode finale:
    • Nu pot fi suprascrise în subclase
public class Parinte {
    public final void metodaFinala() {
        // implementare care nu poate fi modificată în subclase
    }
}
  1. 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:

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:

Compararea Obiectelor

În Java, există două metode principale pentru a compara obiecte:

  1. Operatorul == compară referințele (dacă două variabile referă același obiect)
  2. Metoda equals() compară conținutul obiectelor (valorile)

Metoda equals()

Semnătură: public boolean equals(Object obj)

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():

  1. Reflexivitate: Pentru orice obiect x, x.equals(x) trebuie să returneze true
  2. Simetrie: Pentru orice obiect x și y, dacă x.equals(y) returnează true, atunci y.equals(x) trebuie să returneze true
  3. Tranzitivitate: Pentru orice obiecte x, y și z, dacă x.equals(y) și y.equals(z) returnează true, atunci x.equals(z) trebuie să returneze true
  4. Consistență: Pentru orice obiecte x și y, apeluri multiple ale x.equals(y) trebuie să returneze constant true sau false, presupunând că nu s-a modificat nicio informație
  5. Pentru orice obiect non-null x, x.equals(null) trebuie să returneze false

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

public class ContBancar {
    public void depunere(double suma) {
        // Metodă accesibilă din orice loc
    }
}

protected

public class Animal {
    protected void respira() {
        // Accesibil în același pachet și în subclase
    }
}

default (fără specificator)

class Helper {
    void ajuta() {
        // Accesibil doar în același pachet
    }
}

private

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:

Cum funcționează Garbage Collector

  1. Identifică obiectele care nu mai sunt referite de nicio variabilă accesibilă
  2. Apelează metoda finalize() (dacă este suprascrisă) înainte de ștergerea obiectului
  3. 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