Încapsularea

Încapsularea este una din proprietățile fundamentale ale claselor în programarea orientată pe obiecte.

Câmpurile, constructorii și metodele dintr-o clasă pot fi încapsulate, astfel încât să nu fie vizibile din exteriorul clasei sau instanței în care se află. Aceasta se realizează folosind la declararea câmpului, constructorului sau metodei respective modificatorul private.
 
De exemplu, prin declarația de câmpuri
    private double a, b, c;
se creează câmpurile private a, b, c care nu sunt vizibile din exteriorul instanței în care se afla. În mod similar, prin declarația de metodă
    private int ex1(int k) {
      return 2*k+1);
    }
se declară metoda privată ex1.

Câmpurile și metodele declarate astfel se numesc private. În opoziție cu acestea, sunt câmpurile și metodele publice, care sunt declarate folosind modificatorul public și sunt vizibile din orice altă clasă.

Modificatori de acces pentru câmpuri și metode

În limbajul Java există trei modificatori de acces pentru câmpuri și metode:
  - private - pentru a specifica câmpuri sau metode private;
  - public - pentru a specifica câmpuri sau metode publice;
  - protected - pentru a specifica câmpuri sau metode protejate (care vor fi prezentate în secțiunea despre moștenire).
Membrii privati ai claselor (câmpuri sau metode) sunt accesibili numai din clasa respectivă. Membrii publici sunt accesibili din orice clasă. Membrii protejati sunt accesibili numai din clasa în care se află sau din subclasele acesteia.
Dacă la declararea câmpurilor sau metodelor nu se folosesc modificatori de acces, acestea sunt considerate vizibile numai din clasele care sunt situate în același pachet cu clasa căreia îi aparțin. În particular, pentru clasele declarate de către noi, aceste câmpuri și metode sunt vizibile numai din clasele situate pe disc în același director. Se spune, în astfel de cazuri, că modul de acces este prietenos (engleză: friendly) sau de pachet (engleză: package).

Declararea constructorilor

Constructorii sunt utilizati impreuna cu operatorul new pentru a creea instanțe ale claselor. Constructorii pot fi impliciți sau expliciți.
Constructorii, ca și metodele, sunt niste subprograme. Față de metode, constructorii prezintă următoarele trăsături specifice:
  - numele constructorului este întotdeauna același cu al clasei căreia îi aparține;
  - constructorul nu întoarce o valoare. În consecință, la declararea constructorului nu se specifică tipul valorii întoarse, ca la metode;
  - constructorii nu pot fi statici;
  - invocarea constructorilor se face numai prin operatorul new.

Ca și în cazul metodelor, o clasă poate avea mai multi constructori, care sa difere între ei prin signatură.

Constructorul implicit

Dacă într-o clasă nu este declarat explicit nici un constructor, ea are un constructor implicit. Acest constructor nu are argumente, iar efectul lui constă în inițializarea tuturor câmpurilor instanței care se creează cu valorile implicite corespunzătoare tipurilor câmpurilor respective.
ATENȚIE: dacă clasa are unul sau mai multi constructori declarați explicit, ea nu mai are constructor implicit.

Exemplu: în aplicația Cercuri din fișierul Cercuri.java, la crearea instanțelor clasei Cerc1 s-a folosit constructorul implicit al acestei clase.

Constructori expliciți

Declararea constructorului se face sub forma
    modificator_acces nume_clasa(declaratii_de_argumente) {
        corpul_constructorului
    }
Se observă imediat că declararea constructorului se face la fel cu a unei metode, cu deosebirea că lipsește tipul valorii întoarse, iar numele constructorului este cel al clasei. Modificatorul de acces al constructorului este, cel mai frecvent, public. El poate, totuși, sa lipsească dacă se consideră că instanțierea clasei se va face numai în metode ale claselor din același pachet.

În corpul constructorului pot fi programate orice fel de acțiuni care trebuie executate imediat după ce se alocă în memorie spațiu pentru o instanță a clasei respective. Cel mai frecvent, în corpul constructorilor se inițializează valorile câmpurilor instanței nou create.
 
Exemplu

În fișierul Cercuri1.java este declarată clasa Cerc în modul următor:
 
class Cerc {
  public static final double PI=3.141592653589793;
  private double r;

  public Cerc(double raza) {
    r=raza;
  }

  public double raza() {
    return r;
  }

  public double arie() {
    return PI*r*r;
  }

  public double circumferinta() {
    return 2*PI*r;
  }

  public static double arie(double r) {
    return PI*r*r;
  }

  public static double circumferinta(double r) {
    return 2*PI*r;
  }
}

Clasa Cerc are atât metodele de instanță, cât și metodele statice pentru calcularea ariei și circumferinței, care existau în clasele Cerc1 și Cerc2 din exemplul dat în fișierul Cercuri.java. În plus, remarcăm următoarele:
  - câmpul r1 (raza cercului) a fost declarat privat, deci el nu este accesibil din exteriorul clasei;
  - s-a declarat un constructor care, la crearea unui obiect din clasa Cerc, inițializează câmpul r1. Întrucât clasa Cerc nu conține nici o metodă prin care să se modifice valoarea acestui câmp, raza cercului nu mai poate fi modificată după ce acesta a fost creat, așa cum era posibil în cazul instanțelor clasei Cerc1.

În același fișier sursă, este declarata și clasa Cercuri1, în care se utilizeaza clasa Cerc. Aplicația menționată este declarată astfel:
 
/* Aplicatia in care se utilizeaza cele doua clase de cercuri
   declarate mai sus
*/

class Cercuri1 {
  public static void main(String args[]) {
    double r1=1, r2=7.32;
    /* Instantierea a doua cercuri */
    Cerc c1=new Cerc(r1), c2=new Cerc(r2);
    /* Utilizarea metodelor de instanta */
    System.out.println("Utilizand metodele de instanta:");
    System.out.println("Pentru cercul c1:\n aria="+c1.arie()+
      " circumferinta="+c1.circumferinta()+" raza="+c1.raza());
    System.out.println("Pentru cercul c2:\n aria="+c2.arie()+
      " circumferinta="+c2.circumferinta()+" raza="+c2.raza());
    /* Utilizarea metodelor statice */
    System.out.println("Folosind metodele statice ale clasei Cerc:");
    System.out.println("Pentru raza r1: aria="+Cerc.arie(r1)+
      " circumferinta="+Cerc2.circumferinta(r1));
    System.out.println("Pentru raza r2: aria="+Cerc.arie(r2)+
      " circumferinta="+Cerc2.circumferinta(r2));
    System.out.println("Pentru raza r=9.23 aria="+Cerc.arie(9.23)+
      " circumferinta="+Cerc.circumferinta(9.23));
    /* Acelasi calcul, facut calificand numele metodelor statice prin referinte la instante ale clasei Cerc
    */
    System.out.println("Aria cercului cu raza 9.23: "+
      c1.arie(9.23)+"  "+c2.arie(9.23));
  }
}

Se observă că inițializarea celor două cercuri (instanțe ale clasei Cerc) c1 și c2 s-a făcut folosind constructorul Cerc(double raza). După ce a fost construit cercul, raza lui nu mai poate fi modificată. Calculara ariei cercului c1 se face invocând metoda c1.arie(), care aparține instanței c1. În acest caz, metoda nu are argumente, deoarece se va folsi raza cercului c1
Aria unui cerc oarecare poate fi calculată însă și invocând metoda staticăCerc.arie(raza), căreia însă i se dă ca argument raza cercului. Chiar dacă această metodă statică este invocată prin intermediul referinței la o instanță sub forma c1.arie(raza), nu se va folosi în calcul raza instanței c1, ci raza primită ca argument. Compilatorul face distincție intre metodele arie() și arie(double raza) întrucât au semnături diferite.



© Copyright 2000 - Severin BUMBARU, Universitatea "Dunărea de Jos" din Galați