Obiecte Java

Programarea orientată pe obiecte (POO) reprezintă unul dintre cele mai importante paradigme de programare din lumea modernă a dezvoltării software. În centrul acestei paradigme se află conceptul de "obiect" - o abstracție care permite programatorilor să modeleze entități din lumea reală într-un mod intuitiv și eficient. Java, fiind un limbaj complet orientat pe obiecte, a fost proiectat de la bază pentru a facilita și promova această abordare.

Când învățăm Java, înțelegerea obiectelor și a mecanismelor asociate devine fundamentală pentru dezvoltarea aplicațiilor robuste și ușor de întreținut. Obiectele în Java reprezintă mai mult decât simple structuri de date; ele înglobează atât datele (starea), cât și comportamentul (funcționalitatea) entităților pe care le modelează.

În acest articol, vom explora în profunzime conceptul de obiect în Java, pornind de la definiția și caracteristicile sale esențiale. Vom analiza diferența crucială dintre o clasă (tiparul) și un obiect (instanța), precum și modalitățile prin care putem crea și manipula obiecte. De asemenea, vom examina în detaliu componentele care definesc o clasă: variabilele (atributele) și metodele (comportamentele), împreună cu modificatorii care controlează accesul și comportamentul acestora.

Ce este un obiect în Java?

În Java, un obiect reprezintă o instanță concretă a unei clase, fiind o entitate fundamentală a programării orientate pe obiecte (POO). Putem înțelege un obiect ca o colecție de date și comportamente care funcționează ca o unitate. Fiecare obiect are o stare (definită prin atributele sau variabilele sale) și un comportament (definit prin metodele sale).

Pentru a înțelege mai bine, să ne gândim la un exemplu din viața reală: o mașină. În lumea reală, o mașină are caracteristici precum culoare, model, anul fabricației și comportamente precum accelerare, frânare sau virare. În Java, acestea ar fi reprezentate astfel:

  • Starea mașinii: variabile precum culoare, model, anFabricatie
  • Comportamentul mașinii: metode precum accelereaza(), franeaza(), vireazaStanga()

Obiectele constituie baza programării în Java, permițând organizarea logică a codului într-un mod ce reflectă entitățile din lumea reală. Această abordare face codul mai ușor de înțeles, întreținut și extins.

Caracteristicile unui obiect

Un obiect în Java are următoarele caracteristici principale:

1. Stare

Starea unui obiect este reprezentată de valorile variabilelor sale la un moment dat. Aceste variabile se numesc și atribute sau câmpuri ale obiectului.

public class Masina {
    String culoare = "roșu";
    String model = "Dacia";
    int anFabricatie = 2023;
    int vitezaCurenta = 0;
}

În acest exemplu, starea unei instanțe a clasei Masina este definită de valorile variabilelor culoare, model, anFabricatie și vitezaCurenta.

2. Comportament

Comportamentul unui obiect este definit prin metodele sale, care reprezintă acțiunile pe care obiectul le poate efectua.

public class Masina {
    // Variabilele definite anterior
    
    void accelereaza(int increment) {
        vitezaCurenta += increment;
    }
    
    void franeaza() {
        vitezaCurenta = 0;
    }
    
    String obtineDetalii() {
        return model + " (" + anFabricatie + "), culoare " + culoare;
    }
}

3. Identitate

Fiecare obiect are o identitate unică în memoria calculatorului. Chiar dacă două obiecte au exact aceeași stare (aceleași valori pentru atribute), ele sunt considerate entități separate în Java.

4. Încapsulare

Obiectele încapsulează datele și metodele care operează asupra acestor date într-o singură unitate. Această caracteristică permite ascunderea detaliilor de implementare și expunerea doar a funcționalităților necesare.

5. Interacțiune prin mesaje

Obiectele interacționează între ele prin apeluri de metode, care pot fi considerate ca "trimiterea de mesaje" între obiecte.

Diferența dintre clasă și obiect

Înțelegerea distincției dintre o clasă și un obiect este fundamentală în programarea orientată pe obiecte:

Clasa

  • Este un șablon sau un blueprint care definește structura și comportamentul obiectelor
  • Definește tipurile de date și metodele disponibile pentru obiecte
  • Nu ocupă spațiu în memorie până când nu sunt create instanțe (obiecte)
  • Este ca un tipar pentru fabricarea obiectelor

Obiectul

  • Este o instanță concretă a unei clase
  • Reprezintă o entitate reală care ocupă spațiu în memorie
  • Are valori specifice pentru variabilele definite în clasă
  • Poate executa metodele definite în clasă

Pentru a ilustra această diferență, să considerăm clasa Masina și câteva obiecte create pe baza acestei clase:

public class Masina {
    String culoare;
    String model;
    int anFabricatie;
    
    // Metode
}

// Crearea obiectelor
Masina masina1 = new Masina();
masina1.culoare = "roșu";
masina1.model = "Dacia";
masina1.anFabricatie = 2023;

Masina masina2 = new Masina();
masina2.culoare = "albastru";
masina2.model = "Ford";
masina2.anFabricatie = 2022;

În acest exemplu, Masina este clasa (tiparul), iar masina1 și masina2 sunt obiecte (instanțe concrete ale clasei). Fiecare obiect are propria stare, distinctă de celelalte obiecte.

Stabilirea modificatorilor clasei

În Java, o clasă poate avea diferiți modificatori care controlează accesibilitatea și comportamentul său. Aceștia sunt plasați înaintea cuvântului cheie class în declarație.

Modificatori de acces pentru clase

  1. Public: O clasă declarată cu modificatorul public este accesibilă din orice alt pachet.
public class ClasaPublica {
    // Implementare
}
  1. Default (fără modificator): Dacă nu specificăm niciun modificator, clasa are acces la nivel de pachet, ceea ce înseamnă că este accesibilă doar din același pachet.
class ClasaDefault {
    // Implementare
}

Alți modificatori pentru clase

  1. Final: O clasă declarată final nu poate fi extinsă (nu poate avea subclase).
public final class ClasaFinala {
    // Implementare
}
  1. Abstract: O clasă abstractă nu poate fi instanțiată direct, ci servește ca bază pentru subclase.
public abstract class ClasaAbstracta {
    // Implementare
    
    // Poate conține metode abstracte
    public abstract void metodaAbstracta();
}
  1. Static: Acest modificator poate fi aplicat doar claselor interne (nested classes), nu claselor de nivel superior.
public class ClasaExterna {
    public static class ClasaInterna {
        // Implementare
    }
}

Este important de menționat că nu putem combina orice modificatori. De exemplu, o clasă nu poate fi simultan abstract și final, deoarece aceste concepte sunt contradictorii.

Crearea unui obiect în Java

În Java, există mai multe modalități de a crea obiecte. Vom examina cele mai comune abordări:

1. Utilizând operatorul new

Cea mai frecventă metodă de creare a unui obiect este utilizarea operatorului new, urmat de un apel al constructorului clasei:

public class Persoana {
    String nume;
    int varsta;
    
    // Constructor implicit
    public Persoana() {
        nume = "Necunoscut";
        varsta = 0;
    }
    
    // Constructor cu parametri
    public Persoana(String nume, int varsta) {
        this.nume = nume;
        this.varsta = varsta;
    }
}

// Crearea obiectelor
Persoana persoana1 = new Persoana();  // Utilizează constructorul implicit
Persoana persoana2 = new Persoana("Ana", 25);  // Utilizează constructorul cu parametri

2. Utilizând metoda newInstance()

O altă modalitate de a crea obiecte este utilizarea metodei newInstance() din clasa Class:

try {
    Class<?> cls = Class.forName("Persoana");
    Persoana persoana = (Persoana) cls.newInstance();  // Apelează constructorul implicit
} catch (Exception e) {
    e.printStackTrace();
}

Această abordare este utilă în situațiile în care numele clasei este cunoscut doar la runtime.

3. Utilizând metode factory

Metodele factory sunt metode statice care returnează o instanță a clasei:

public class Persoana {
    String nume;
    int varsta;
    
    private Persoana(String nume, int varsta) {
        this.nume = nume;
        this.varsta = varsta;
    }
    
    // Metodă factory
    public static Persoana creeazaPersoana(String nume, int varsta) {
        return new Persoana(nume, varsta);
    }
}

// Utilizarea metodei factory
Persoana persoana = Persoana.creeazaPersoana("Ion", 30);

4. Utilizând clonarea

Putem crea un obiect nou bazat pe un obiect existent prin clonare:

public class Persoana implements Cloneable {
    String nume;
    int varsta;
    
    // Constructor și alte metode
    
    @Override
    public Persoana clone() throws CloneNotSupportedException {
        return (Persoana) super.clone();
    }
}

// Clonarea unui obiect
Persoana persoanaOriginala = new Persoana("Maria", 28);
try {
    Persoana persoanaClonata = persoanaOriginala.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

5. Utilizând deserializarea

Obiectele serializate pot fi recreate prin deserializare:

// Deserializarea unui obiect
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("persoana.ser"))) {
    Persoana persoana = (Persoana) in.readObject();
} catch (Exception e) {
    e.printStackTrace();
}

Variabilele unei clase

Variabilele unei clase, cunoscute și sub numele de câmpuri sau atribute, reprezintă datele asociate cu obiectele create din acea clasă. Aceste variabile definesc starea obiectelor.

Tipuri de variabile ale clasei

În Java, există trei tipuri principale de variabile ale clasei:

  1. Variabile de instanță: Aceste variabile sunt declarate în cadrul clasei, dar în afara metodelor. Fiecare obiect al clasei are propriile copii ale acestor variabile.
public class Student {
    String nume;           // Variabilă de instanță
    int numarMatricol;     // Variabilă de instanță
    double medie;          // Variabilă de instanță
}
  1. Variabile statice (de clasă): Aceste variabile sunt declarate cu modificatorul static și aparțin clasei, nu obiectelor individuale. Toate instanțele clasei împărtășesc aceeași variabilă statică.
public class Contor {
    static int numarTotal = 0;  // Variabilă statică
    
    public Contor() {
        numarTotal++;  // Incrementează contorul la fiecare creare de obiect
    }
}
  1. Variabile locale: Aceste variabile sunt declarate în interiorul metodelor și există doar pe durata execuției metodei respective.
public class Calculator {
    public int aduna(int a, int b) {
        int suma = a + b;  // Variabilă locală
        return suma;
    }
}

Declararea variabilelor clasei

Variabilele clasei sunt de obicei declarate la începutul corpului clasei:

public class Angajat {
    // Declararea variabilelor clasei
    String nume;
    String prenume;
    int varsta;
    double salariu;
    String departament;
    boolean esteManager;
    
    // Restul clasei (constructori, metode, etc.)
}

Inițializarea variabilelor clasei

Variabilele clasei pot fi inițializate în mai multe moduri:

  1. La declarare:
public class Produs {
    String nume = "Nedefinit";
    double pret = 0.0;
    int stoc = 0;
}
  1. În blocuri de inițializare:
public class Produs {
    String nume;
    double pret;
    int stoc;
    
    // Bloc de inițializare
    {
        nume = "Nedefinit";
        pret = 0.0;
        stoc = 0;
    }
}
  1. În constructori:
public class Produs {
    String nume;
    double pret;
    int stoc;
    
    public Produs() {
        nume = "Nedefinit";
        pret = 0.0;
        stoc = 0;
    }
}

Modificatori variabilelor unei clase

În Java, variabilele clasei pot avea diferiți modificatori care controlează accesibilitatea, natura și comportamentul lor.

Modificatori de acces

  1. public: Variabilele declarate public sunt accesibile din orice clasă.
public class Angajat {
    public String nume;  // Accesibilă din orice clasă
}
  1. private: Variabilele declarate private sunt accesibile doar în interiorul clasei în care sunt declarate.
public class ContBancar {
    private double sold;  // Accesibilă doar în clasa ContBancar
}
  1. protected: Variabilele declarate protected sunt accesibile în interiorul pachetului și în subclase.
public class Animal {
    protected String specie;  // Accesibilă în pachet și subclase
}
  1. default (fără modificator): Dacă nu specificăm un modificator de acces, variabila are acces la nivel de pachet.
public class Carte {
    String titlu;  // Accesibilă doar în același pachet
}

Alți modificatori

  1. static: Variabilele declarate static aparțin clasei, nu instanțelor individuale.
public class Contor {
    public static int numarAccesari = 0;  // Aparține clasei, nu obiectelor
}
  1. final: Variabilele declarate final nu pot fi modificate după inițializare.
public class Constante {
    public final double PI = 3.14159;  // Nu poate fi modificată
}
  1. transient: Variabilele declarate transient nu sunt serializate când obiectul este serializat.
public class Utilizator implements Serializable {
    private String nume;
    private transient String parola;  // Nu va fi serializată
}
  1. volatile: Variabilele declarate volatile sunt accesate direct din memoria principală, fiind utile în programarea concurentă.
public class Status {
    private volatile boolean activ;  // Utilizată în contextul firelor de execuție
}

Combinarea modificatorilor

Modificatorii pot fi combinați pentru a obține comportamentul dorit:

public class Configuratie {
    // O constantă publică, accesibilă tuturor, care aparține clasei
    public static final String VERSIUNE = "1.0.0";
    
    // O variabilă privată care aparține clasei
    private static int numarInstante = 0;
    
    // O variabilă finală de instanță
    private final String id;
    
    public Configuratie(String id) {
        this.id = id;
        numarInstante++;
    }
}

Metodele unei clase

Metodele reprezintă comportamentul obiectelor și definesc acțiunile pe care acestea le pot efectua. În Java, metodele sunt declarate în interiorul clasei și pot manipula datele clasei.

Structura unei metode

O metodă în Java are următoarea structură generală:

[modificatori] tip_returnare nume_metoda([parametri]) [excepții] {
    // Corp metodă
    [return valoare;]
}

Unde:

  • modificatori: Specifică accesibilitatea și alte caracteristici ale metodei
  • tip_returnare: Tipul de date returnat de metodă (sau void dacă nu returnează nimic)
  • nume_metoda: Identificatorul metodei
  • parametri: Lista de parametri acceptați de metodă
  • excepții: Excepțiile care pot fi aruncate de metodă
  • corp metodă: Implementarea metodei
  • return: Valoarea returnată (dacă metoda nu este void)

Tipuri de metode

  1. Metode de instanță: Aceste metode aparțin obiectelor și pot accesa variabilele de instanță.
public class Calculator {
    public int aduna(int a, int b) {
        return a + b;
    }
}

// Utilizare
Calculator calc = new Calculator();
int suma = calc.aduna(5, 3);  // Apel al metodei de instanță
  1. Metode statice: Aceste metode aparțin clasei și nu pot accesa variabilele de instanță direct.
public class MathUtils {
    public static int max(int a, int b) {
        return (a > b) ? a : b;
    }
}

// Utilizare
int maxim = MathUtils.max(10, 7);  // Apel direct, fără instanțiere
  1. Constructori: Metode speciale folosite pentru inițializarea obiectelor.
public class Persoana {
    String nume;
    int varsta;
    
    // Constructor
    public Persoana(String nume, int varsta) {
        this.nume = nume;
        this.varsta = varsta;
    }
}
  1. Metode abstracte: Metode declarate în clase abstracte, fără implementare.
public abstract class Forma {
    public abstract double calculeazaArie();  // Metodă abstractă
}

Supraîncărcarea metodelor (Method Overloading)

Java permite declararea mai multor metode cu același nume, dar cu parametri diferiți:

public class Calculator {
    public int aduna(int a, int b) {
        return a + b;
    }
    
    public double aduna(double a, double b) {
        return a + b;
    }
    
    public int aduna(int a, int b, int c) {
        return a + b + c;
    }
}

Suprascrierea metodelor (Method Overriding)

Metodele din clasa părinte pot fi suprascrise în subclase pentru a oferi o implementare specifică:

public class Animal {
    public void emiteSunet() {
        System.out.println("Sunet generic de animal");
    }
}

public class Caine extends Animal {
    @Override
    public void emiteSunet() {
        System.out.println("Ham ham!");
    }
}

Modificatori de acces a metodelor

Modificatorii de acces pentru metode controlează modul în care acestea pot fi accesate și utilizate de alte clase.

Modificatori de acces principali

  1. public: Metodele declarate public sunt accesibile din orice clasă.
public class Util {
    public void metodaPublica() {
        System.out.println("Această metodă poate fi accesată din orice clasă");
    }
}
  1. private: Metodele declarate private sunt accesibile doar în interiorul clasei în care sunt declarate.
public class Securitate {
    private void verificaAutentificare() {
        System.out.println("Această metodă poate fi accesată doar în interiorul clasei");
    }
}
  1. protected: Metodele declarate protected sunt accesibile în interiorul pachetului și în subclase.
public class Baza {
    protected void metodaProtejata() {
        System.out.println("Accesibilă în pachet și subclase");
    }
}
  1. default (fără modificator): Dacă nu specificăm un modificator de acces, metoda are acces la nivel de pachet.
public class Helper {
    void metodaDefault() {
        System.out.println("Accesibilă doar în același pachet");
    }
}

Alți modificatori pentru metode

  1. static: Metodele declarate static aparțin clasei, nu instanțelor individuale.
public class Utils {
    public static int max(int a, int b) {
        return (a > b) ? a : b;
    }
}
  1. final: Metodele declarate final nu pot fi suprascrise în subclase.
public class Baza {
    public final void metodaFinala() {
        System.out.println("Această metodă nu poate fi suprascrisă");
    }
}
  1. abstract: Metodele declarate abstract nu au implementare și trebuie suprascrise în subclase.
public abstract class Forma {
    public abstract double calculeazaArie();  // Trebuie implementată în subclase
}
  1. synchronized: Metodele declarate synchronized pot fi accesate de un singur fir de execuție la un moment dat.
public class ContBancar {
    private double sold = 0;
    
    public synchronized void depune(double suma) {
        sold += suma;
    }
}
  1. native: Metodele declarate native sunt implementate în cod nativ (C/C++).
public class SistemOperare {
    public native int getMemorieDisponibila();  // Implementată în cod nativ
}

Combinarea modificatorilor

Modificatorii pot fi combinați pentru a obține comportamentul dorit:

public class Exemplu {
    // Metodă publică, statică și finală
    public static final void metodaConstanta() {
        System.out.println("Metodă constantă a clasei");
    }
    
    // Metodă privată și sincronizată
    private synchronized void operatieCritica() {
        System.out.println("Operație critică, accesibilă doar în clasă și sincronizată");
    }
}

În concluzie, obiectele în Java reprezintă fundamentul programării orientate pe obiecte, oferind un mecanism puternic pentru modelarea entităților din lumea reală. Înțelegerea corectă a conceptelor de clasă, obiect, variabile și metode, precum și a modificatorilor acestora, este esențială pentru dezvoltarea unor aplicații Java eficiente și bine structurate mai  vezi: Structura lexicală a limbajului Java. Prin stăpânirea acestor concepte, programatorii pot crea sisteme modulare, ușor de întreținut și extins, care să răspundă cerințelor din ce în ce mai complexe ale aplicațiilor moderne.

Share on


Echipa conspecte.com, crede cu adevărat că studenții care studiază devin următoarea generație de aventurieri și lideri cu gândire globală - și dorim cât mai mulți dintre voi să o facă!