Se afișează postările cu eticheta void. Afișați toate postările
Se afișează postările cu eticheta void. Afișați toate postările

duminică, 7 septembrie 2025

Clase și obiecte. Sintaxă și semantică

Clasa stă de fapt la baza programării orientate e obiecte, pe ea este construit întregul limbaj Java, deoarece clasa definește obiectul.

O clasă reprezintă un șablon sau un tip de bază pentru crearea obiectelor. Este un tip abstract de date definit de programator. Atunci când definim o clasă nouă creăm un nou tip de date.

O clasă descrie un set de caracteristici (date, atribute sau variabile de instanță) și comportamente (funcționalitate, metode sau funcții) pe care obiectele create din acea clasă le vor avea. Clasa în POO întrunește toate obiectele de una şi aceeași natură, ceea ce înseamnă că obiectele care aparțin uneia și aceleiași clase au una şi aceeași structură şi comportament.

Sintaxa de definire a unei clase este: 

Prima parte din declarația unei clase o constituie modificatorii de acces care sunt opționali. După numele clasei putem specifica, dacă este cazul, faptul că respectiva clasă este subclasă a unei alte clase cu numele nume_super_clasă, sau/şi că implementează una sau mai multe interfeţe ale căror nume trebuie separate prin virgulă.


Corpul unei clase este cuprins între { } şi are ca conţinut:
  • declararea şi inițializarea variabilelor de instanţă şi de clasă;
  • declararea şi implementarea constructorilor;
  • declararea şi implementarea metodelor de instanţă şi de clasă;
  • declararea unor clase interne.
Reţineţi!
  • într-un fișier Java pot fi definite mai multe clase;
  • într-un fișier Java numai o clasă poate avea modificatorul public;
  • fișierul Java ce conține o clasă publică trebuie să fie cu același nume ca și clasa publică.
O clasă poate avea unul din următoarele cuvinte rezervate în declarația acestora:

Exemplu de declarație de clasă: 


În Java orice clasă conţine 2 tipuri de elemente : atribute (variabilele) şi metode

Variabilele unei clase se declară înaintea metodelor, (deşi nu este impus de compilator acest lucru), şi sunt vizibile în toate metodele respectivei clase.

Variabilele declarate în cadrul unei metode sunt locale metodei respectivei.

O variabilă de declară respectând sintaxa :

[modificatori] tip_variabila nume_variabila [=valoareInitiala];

Modificatorii pot fi :
1) modificatori de acces:

2) unul din cuvintele rezervate:
- static: indică că variabila este variabilă de clasă şi nu de instanță;
             De exemplu: static int varClasa; int varInstanta;
- final: indică faptul că valoarea variabile nu poate fi modificată, declararea constantelor;
             De exemplu: final double PI = 3.14;
- transient – folosit pentru a specifica dacă variabila membră participă în procesul de serializare sau nu (detalii tema ,,Serializarea obiectelor’’)

Exemplu:
class Exemplu {
double x;
//variabila vizibila in clasa data si pachetul din care face parte clasa
protected static int n; //vizibila in clasa data si in subclasele același pachet cu clasa data
public String s="abc"; // variabila s de tip șir de caractere fi vizibila oriunde
final int MAX=1000; // constanta de tip întreg
}

O metodă se declară respectând sintaxa:

[modificatori] tipReturnat numeMetoda ([lista_argumente])
[throws tipExceptie1, tipExceptie2,...]{
// corpul metodei
}


Modificatorii pot fi
1) un specificator de acces: public, protected, private;
2) unul din cuvintele rezervate :
 - static: semnifică că metoda este de clasă şi nu de instanţă.
       De exemplu: void metodaInstanta(); 
             static void metodaClasa();
- abstract: semnifică că o metodă este abstractă,adică nu are implementare şi obligatoriu face parte dintr-o clasă abstractă. (tema Clase şi metode abstracte)
- final: indică că metoda nu mai poate fi supradefinită în subclasele clasei în care ea este definită ca fiind finală. Se folosești atunci când nu dorim ca metoda să fie modificată în subclasele clasei date;
- synchronized: este folosit în cazul în care se lucrează cu mai multe fire de execuție.

O metodă poate sau nu să returneze o valoare la finisarea execuției. Tipul returnat poate fi un tip primitiv de date sau o referință la un obiect al unei clase. 

Atunci când o metodă nu returnează nimic trebuie obligatoriu de specificat cuvântul cheie ,,void’’ ca fiind tipul returnat de aceasta.
De exemplu:
                   public void afisare(){
           System.out.println("Rezultat ");
         }
Dacă o metodă trebuie să returneze o valoare, la terminarea funcției trebuie să apară obligatoriu instrucțiunea return urmată de rezultat compatibil cu tipul metodei.
De exemplu:
int metoda(){ return 1; // corect
}
int metoda(){ return 1.5; //eroare
}
int metoda(){ return (int)1.5;
}

Dacă valoarea returnată este o referință la un obiect al unei clase atunci clasa obiectului returnat trebuie să coincidă sau să fie o subclasă a clasei specificate la declararea metodei.
De exemplu, fie clasa Poligon şi subclasa ei Patrat:

a) Poligon metoda1(){
    Poligon p=new Poligon();
    Patrat t=new Patrat();
    if (...) return p
      else t
  }

b) Patrat metoda2(){
    Poligon p=new Poligon();
    Patrat t=new Patrat();
    if (...) return p;//ilegal
    else t; 
  }

Lista de argumente este opţională la declararea metodei, dar dacă aceasta este atunci va avea forma:
<tipVariabila1> <Variabila1> , ... , <tipVariabilaN> <VariabilaN>
variabila1,...,variabilaN se numesc parametri formali.
Parametri formali sunt acei parametri care apar la definirea metodei. La apelarea metodei sunt parametri actuali, iar valorile acestora se transmite parametrilor formali.
Nu este posibil ca doi parametri formali să conțină același nume.


După cum am meționat clasa este un șablon sau model după care se crează obiecte. Atunci când creăm un obiect, în limbaj POO, spunem că instanțiem o clasă.

Deci în cele ce urmează vom studia cum se instanțiază o clasă. Pentru ceasta se va respecta sintaxa: 

Denumire_clasă denumire_obiect = new Denumire_clasă();

Odată creat obiectul poate fi folosit pentru a: afla informații despre obiect, schimba starea obiectului, executa unele acțiuni.

Obiectul accesează metodele şi datele clasei sale prin intermediul operatorului ,, .’’ folosind sintaxa:
denumire_Obiect.variabilă;
denumire_Obiect.numeMetoda();

Exemple:
elev1.nume="Ion";
elev1.virsta=20;
elev1.bursa();
elev1.setNume("Ion");

Deci procesul prin care creăm obiecte pentru o clasă, de fapt în POO poartă denumirea de instanțierea unei clase și de fapt implică următoarele:

1) declararea variabilei de tipul clasei care va referi un obiect: 
numeClasa numeObiect;
    De exemplu: Elev elev1;

2) instanţiere – se realizează cu operatorul new() şi are ca efect crearea obiectului cu alocarea spaţiului de memorie corespunzător: 
numeObiect = new numeClasa();

    De exemplu: elev1 = new Elev();

3) iniţializare – se realizează prin intermediul constructorilor clasei respective, are loc de fapt împreună cu instanţierea, urmează imediat după operatorul new.

Parantezele rotunde de după identificatorul numeClasa(); indică că acolo este de fapt un apel la unul din constructorii clasei. Deci instanţierea şi iniţializarea au forma:

numeObiect = new numeClasa([argumente_constructor]);

De exemplu: elev1 = new Elev("Ion",20);
Sintaxa de declarare și instanțiere pot fi scrise în codul sursă atât separat, cât și împreună printr-o singură construcție de forma: 
 
numeClasa numeObiect = new numeClasa([argumente_constructor]);

De exemplu: Elev elev1 = new Elev("Ion",20); 



vineri, 22 martie 2024

Interfețe în limbajul Java

 

O interfață  este o colecție de metode și date membre publice. Metodele într-o interfață sunt abstracte, adică este prezentă doar semnătura metodelor, implementarea acestora fiind realizată de clasa care va folosi interfață dată.

Sintaxa:

[public] interface NumeInterfata

                    [extends ListaInterfete]

{

     // declarații de membri de interfață

}

De exemplu:

interface Animal {
    void maninca();
    void doarme();
}

Reguli de lucru cu interfețele în Java

  1. Numele interfeței nu coincide cu numele altei clase sau interfeţe din acelaşi pachet.
  2. Dacă declarația unei interfeţe conţine clauza extends atunci interfața va moșteni toate metodele şi constantele interfețelor enumerate în <ListaInterfete>, care se numesc superinterfeţe.
  3. Nu există o superinterfaţă generală cum este clasa Object pentru superclase.
  4. Corpul unei metode într-o interfață este ;, dar începând cu Java 8, în interfață pot fi metode static și default.
  5. Toți membri interfeței sunt considerați implicit public, dar dacă modificatorul public este specificat atunci sunt accesibili şi înafara pachetului.
  6. Deoarece variabilele unei interfeţe sunt considerate constante acestea trebuie să fie inițializate altfel se va produce eroare de compilare.
  7. Metode cu aceeași semnătură, dar tip de return diferit nu pot fi folosite în interfeţe.
  8. Variabilele unei interfeţe sunt considerate implicit public, static şi final. Chiar dacă veți omite aceste cuvinte rezervate vor fi adăugate în mod automat de compilatorul Java la faza de compilare, în fișierul *.class.
  9. E posibil ca o clasă să folosească variabilele cu același nume dintr-o altă interfață, în acest caz la accesarea acestora trebuie de respectat sintaxa:  numeInterfata.numeVariabila
  10. La declararea unei metode nu este permisă apariția tuturor modificatorilor de acces, doar public sau abstract.
  11. Dacă o clasă implementează 2 interfețe ce au metodă cu același nume este de ajuns să implementăm o singură metodă.
  12. Nu este binevenit de a folosi metode cu același nume într-o interfață sau mai multe interfeţe să conțină metode cu acelaşi nume.
  13. Interfețele nu au câmpuri și nici constructori. Nu pot fi insanțiate, și nu pot păstra starea obiectelor.

Pentru ca o clasă să implementeze o interfață trebuie să respecte sintaxa :

class numeClasa implements Interfata1,...,InterfataN { ...

}

De exemplu:

class Cal implements Animal{
    void manica(){...}
    void doarme(){...}
}

O clasă poate implementa orice număr de interfețe. Clasa ce implementează interfața trebuie obligatoriu să conțină cod pentru toate metodele interfeței, din acest motiv o interfață implementată într-o clasă nu trebuie modificată, dacă modificăm interfața obligatoriu modificăm şi codul sursă al clasei ce o implementează.
interface A {
// membrii interfeței A
}

interface B {
// membrii interfeței B
}

class C implements A, B {
// implementarea metodelor abstracte din A
// implementarea metodelor abstracte din B
}

O interfață poate extinde altă interfață:

interface A {
// membrii interfeței A
}
interface B extends A {
// membrii interfeței B
}
class C implements B {
// implementarea metodelor abstracte din A
// implementarea metodelor abstracte din B
}

Chiar poate extinde mai multe interfețe: 

interface A {
// membrii interfeței A
}
interface B {
// membrii interfeței B
}
interface C extends A, B {
// membrii interfeței C
}
class D implements C {
// implementarea metodelor abstracte din A
// implementarea metodelor abstracte din B
// implementarea metodelor abstracte din C
}


Clasa ce implementează o interfață poate avea şi metode specifice ei, nu doar metodele interfeței.
O interfață poate extinde o altă interfață, dar nu o poate implementa.

Rețineți! 

Exemplul_1: 

interface Poligon {

    void getAria(int ... laturi);

}

class Dreptunghi implements Poligon {

 public void getAria(int ... laturi) {

 if (laturi.length==2)

  System.out.println("Aria dreptunghiului este " + (laturi[0] * laturi[1]));

}}

class Patrat implements Poligon {

 public void getAria(int ... laturi) {

  if (laturi.length==1) System.out.println("Aria patratului este "+(Math.pow(laturi[0], 2)));

}

}

class Main {

    public static void main(String[] args) {

    Dreptunghi r1 = new Dreptunghi ();

      r1.getAria(5, 6);

      Patrat p1 = new Patrat();

      p1.getAria(5);

    }

}

În Java nu poate fi implementată moștenirea multiplă la nivel de stare, dar interfețele permit realizarea moștenirii multiple la nivel de comportament. 

Exemplul_2: 

interface Masina{

  int  viteza=90;

  public void distanta();

}

interface Autobus{

  int distanta=100;

  public void viteza();

}

class Vehicul  implements Masina,Autobus {

  public void distanta(){

   int  distanta=viteza*100;

   System.out.println("Distanta parcursa este "+distanta);

  }

  public void viteza(){

   int viteza=distanta/100;

   System.out.println("Viteza = "+viteza);

   }

}

class DemoVehicule{

 public static void main(String args[]){

  System.out.println("Vehicul");

  Vehicul v1=new Vehicul();

  v1.distanta();

  v1.viteza();

}}


Exemplu: 

interface Interfata_1{ public void metoda_1();

}

interface Interfata_2 extends Interfata_1 { public void metoda_2();

}

class DemoInterfete implements Interfata_2{

    public void metoda_1(){

     System.out.println("Aici metoda 1");

    }

    public void metoda_2(){

     System.out.println("Aici metoda 2");

    }

    public static void main(String args[]){

    DemoInterfete obj = new DemoInterfete();

     obj.metoda_2();

    }}

Notă! Interfețele nu pot fi instanțiate însă putem crea variabile referință de tip interfață. De exemplu, dacă în metoda main() în exemplul de mai sus vom folosi construcția:

public static void main(String args[]){

    Interfata_2 obj = new DemoInterfete();

     obj.metoda_2();

}

Aceasta este validă, iar programul va afișa același rezultat. Vor putea fi apelate pentru obiectul obj acele metode din Interfata_2 care au implementare în clasa dată. Variabilele referință de tip interfață se folosesc doar urmate de instanţierea clasei ce implementează interfața la care face referință variabila. 

Pentru a distinge corect între utilizarea claselor abstracte sau interfețe luați în considerare următoarele aspecte:

  1. Dacă aveți nevoie să descrieți doar comportamentul obiectelor, nu și starea acestora utilizați interfețe. În caz contrar clase abstracte, deoarece clasele abstracte includ atât starea cât și comportamentul obiectelor. O interfață descrie doar comportamentul.
  2. Dacă aveți nevoie să specificați un comportament comun pentru mai multe clase care fac parte din ierarhii diferite utilizați interfețe. De exemplu clasele Om și Masina, nu au nimic comun, fac parte din ierarhii diferite, dar au comun faptul că se deplasează: omul cu picioarele, iar mașina cu ajutorul componentelor tehnice.  Deci, o clasă abstractă conectează clase care sunt foarte strâns legate. În timp ce interfața poate fi implementată de clase care nu au absolut nimic în comun.
  3. Java suportă moștenirea de stare, la nivel de clasă, și moștenire de comportament, la nivel de interfață. Clasele pot implementa orice număr de interfețe, dar pot moșteni o singură clasă. Deci dacă doriți să implementați moștenirea de stare, unde o clasă derivată (subclasă) primește atât comportamentul (metodele) cât și starea (atributele) din clasa de bază (superclasă), utilizați clase sau clase abstracte. Dar dacă doriți să specificați un contract sau specificații de comportament, fără a furniza o implementare implicită atunci utilizați interfețele.  

👌 Analizează și discută!  
  1. Explicați conceptul de interfață în Java și modul în care este utilizată pentru a defini comportamente standard și contracte pentru clasele care o implementează.
  2. Comparați clasele abstracte și interfețele în ceea ce privește caracteristicile, utilizările și restricțiile lor în Java.
  3. Argumentați beneficiile și avantajele utilizării interfețelor în comparație cu clasele abstracte în diverse scenarii de proiectare și dezvoltare a software-ului.
  4. Care este diferența între o interfață și o clasă abstractă în ceea ce privește implementarea metodelor? 



Vă doresc o zi deosebit de frumoasă! ❤️