Tutorial Java SCJP – #17 Modificatori de acces pentru metode si variable, atribute

Modificatorii de acces reprezinta modalitati prin care programatorul poate controla (acorda sau restrictioneaza) accesul la metodele si atributele definite intr-o clasa. Un motiv pentru a utiliza acesti modificatori de access este conceptul POO numit incapsulare, care cere ca atributele sa nu poata si accesate (citire/scriere) direct, ci doar prin metode accesor (cele prefixate cu get si set). Un alt motiv este necesitatea de a controla cum este folosita clasa si cum si ce valori ajung sa fie stocate in variabilele de instanta (atribute). De exemplu, daca se implementeaza clasa Persoana care defineste atributul varsta, nu este de dorit ca un alt programator sa poata initializa direct (cu orice valoare) acest atribut, deoarece poate folosi o valoare negativa.

Acest topic face parte dintr-un tutorial Java 6 accesibil prin Tutorial Java 6 – Continut.

Modificatorii de access utilizati pentru membrii unei clase (metode si atribute) sunt:

Asa cum reiese din scurta descriere a modificatorilor de acces, acestia reprezinta reguli cu privire la dreptul de a accesa membrii (atribute si metode) unei clase din alte clase.

In contextul unei singure clase, aceasta va avea acces intotdeauna la propriile atribute si metode, indiferent de modificatorul de acces al acestora.

Ce inseamna sa vezi sau sa accesezi metoda sau atributul dintr-o clasa

Daca analizam o instanta de variabila sau metoda non-statica (mai mult despre atributul static intr-un articol separat), stim ca pentru a o accesa (apela daca e metoda) avem nevoie de o referinta si de operatorul punct (.).  Dar, pentru ca POO inseamna sa definesti mai mult de o clasa, poti sau nu sa faci acest lucru din alte clase, chiar daca acestea sunt subclase (clase derivate) ale celei analizate.

Deci, in Java, sa vezi metoda sau atributul unei clase, inseamna sa poti sa o apelezi sau sa il accesezi:

Daca se considera clasa ClassA definita in pachetul main:

package main;

public class ClassA{
    private int atributPrivat;    	//privat
    public int atributPublic;      	//public

    //metoda in clasa
    void faCeva(){
	atributPrivat = 10;	//accesibil
	atributPublic = 20;	//accesibil
    }
}

si clasa Main definita in acelasi pachet ce contine metoda statica main:

package main;

public class Main {
    public static void main(String[] args) {
        ClassA ref = new ClassA();
        //atributele publice sunt vizibile - pot fi accesate
        ref.atributPublic = 10;

        //atributele private NU sunt vizibile - NU pot fi accesate
	//eroare de compilare: atributPrivat has private access in...
        ref.atributPrivat = 20;    //eroare de compilare
    }
}

In exemplul anterior, atributul privat atributPrivat definit in clasa ClassA nu poate fi accesat in metoda main() a clasei Main deoarece este privat si nu este vizibil. Situatia este controlata si de compilator care genereaza o eroare de compilare cu mesajul atributPrivat has private access in…. Atributul privat poate fi accesat doar din interiorul clasei parinte, ClassA.

Spre deosebire de atributPrivat, atributul public atributPublic, este vizibil in clasa Main si poate fi accesat fara probleme.

Aceleasi reguli, descrise in exemplul anterior pentru atribute, sunt valabile si pentru metode.

 

Modificatorul de acces – Public

Modificatorul de acces public  este cel mai putin restrictiv deoarece face atributul sau metoda vizibila in orice alta clasa (subclasa sau nu) indiferent de pachetul in care se gaseste.

Daca se considera clasa ClassA definita in pachetul main:

package main;

public class ClassA{
    public int atributPublic;      //public
}

atunci, atributul public este vizibil, sau poate fi accesat in clase din acelasi pachet:

package main;   //acelasi pachet

public class ClassB {
    public static void faCeva()
    {
        ClassA ref = new ClassA();
        ref.atributPublic = 20;
    }
}

atunci, atributul public este vizibil, sau poate fi accesat in subclase ale clasei parinte din acelasi pachet (mai multe despre mostenire intr-un alt articol):

package main;   //acelasi pachet

public class SubClassA extends ClassA {
    public void faCeva(){
       
       ClassA ref = new ClassA();

       //accesibila prin referinta
       ref.atributPublic = 20;

       //accesibila prin mostenire
       this.atributPublic = 30;
    }
}

atunci, atributul public este vizibil, sau poate fi accesat in subclase ale clasei parinte din alte pachete (mai multe despre mostenire intr-un alt articol):

package other;  //alt pachet

import main.ClassA;

public class OtherSubClassA extends ClassA {
    public void faCeva(){

        ClassA ref = new ClassA();

       //accesibila prin referinta
       ref.atributPublic = 20;

       //accesibila prin mostenire
       this.atributPublic = 30;
    }
}

atunci, atributul public este vizibil, sau poate fi accesat in clase din alt pachet:

package other;  //alt pachet

import main.ClassA;

public class ClassC {
    public static void faCeva()
    {
        ClassA ref = new ClassA();
        ref.atributPublic = 20;		//vizibila
    }
}

Modificatorul de acces – Private

Modificator de acces private este cel mai restrictiv deoarece blocheaza accesul la atribut sau metoda din afara clasei parinte fara nicio exceptie.

Deci, pentru private, atributele sau metodele pot fi accesate DOAR din metode apartinand clasei parinte.

package main;

public class ClassA{
    private int atributPrivat;     //privat

    public void doSomething(){
        //vizibila doar in aceeasi clasa
        atributPrivat = 20;
    }
}

Modificatorul de acces – Default

Modificatorul de acces default (atunci cand nu se specifica un modificator de acces) stabileste restrictii intre  public si private, deoarece blocheaza accesul la atribute sau metode din clase ce se gasesc in alt pachet decat clasa in care acestea au fost definite.

Acest modificator de acces este similar cu modificatorul de acces utilizat pentru clase (vezi Tutorial Java SCJP – #13 Packages and Class modificator de access).

Atributele si metodele declarate default sunt accesibile din:

  • aceeasi clasa;
  • alte clase din acelasi pachet;
  • subclase din acelasi pachet;

Pentru clasa ClassA:

package main;

public class ClassA{

    int defaultAttribute;             //default

    public void faCeva(){
        //vizibil in aceeasi clasa
        atributDefault = 20;
    }
}

atributul atributDefault este vizibil in alte clase din acelasi pachet:

package main;   //acelasi pachet

public class ClassB {
    public static void faCeva(){
        ClassA ref = new ClassA();
        ref.atributDefault = 30;
    }
}

si in subclase din acelasi pachet:

package main;   //acelasi pachet

public class SubClassA extends ClassA {
    public void faCeva(){
       
       ClassA ref = new ClassA();

       //accesibil printr-o referinta
       ref.atributDefault = 20;

       //accesibil prin mostenire
       this.atributDefault = 30;
    }
}

Atributele si metodele default NU sunt vizibile in clase sau subclase din alt pachet:

package other;  //alt pachet

import main.ClassA;

public class ClassC {
    public static void faCeva(){
        ClassA ref = new ClassA();
        //NU este vizibil - NU poate fi accesat
        ref.atributDefault = 20;  //eroare de compilare
    }
}

Modificatorul de acces – Protected

Un avantaj al POO este conceptul de mostenire/derivare pentru ca iti permite sa definesti clase noi pe baza unor existente, prin extinderea acestora si nu prin modificarea lor.

Deoarece exista o relatie speciala intre clasa de baza (cea care exista) si subclasa (clasa noua care extinde clasa de baza), se poate utiliza un modificator de acces care face atributele si metodele accesibile DOAR pentru subclase. Acest modificator de acces este protected.

package main;

public class ClassA{

    protected int atributProtected;    //protected

    public void faCeva(){
        //vizibil in aceeasi clasa
        atributProtected = 20;
    }
}

Atributele protected sunt vizibile in:

– clase din acelasi pachet:

package main;   //acelasi pachet

public class ClassB {
    public static void faCeva(){
        ClassA ref = new ClassA();
        ref.atributProtected = 40;
    }
}

– subclase din acelasi pachet (prin mostenire si prin referinte)

package main;   //acelasi pachet

public class SubClassA extends ClassA {
    public void faCeva(){
       
       ClassA ref = new ClassA();

       //accesibil printr-o referinta
       ref.atributDefault = 20;

       //accesibil prin mostenire
       this.atributDefault = 30;
    }
}

– subclase din alte pachete (IMPORTANT ! doar prin mostenire):

package other;  //alt pachet

import main.ClassA;

public class OtherSubClassA extends ClassA {
    public void faCeva(){

        ClassA ref = new ClassA();

       //NU este accesibil prin utilizarea unei referinte
       ref.atributProtected = 20; //eroare de compilare

       //accesibil doar prin mostenire
       this.atributProtected = 30;
    }
}

Atributele si metodele protected NU sunt vizibile in clase din afara pachetului:

package other;  //alt pachet

import main.ClassA;

public class ClassC {
    public static void faCeva(){
        ClassA ref = new ClassA();
        //NU este vizibil - NU poate fi accesat
        ref.atributProtected = 20;  //eroare de compilare
    }
}

Reguli importante pentru testul SCJP

Pentru testul SCJP memorati si intelegeti tabelul urmator care sumarizeaza regulile si scenariile de utilizare a modificatorilor de acces:

Vizibilitate (acces)

public

protected

private

default

Aceeasi clasa

X

X

X

X

Clase in acelasi pachet

X

X

 

X

Subclasa in acelasi pachet

X

X

 

X

Subclasa in alt pachet

X

X

(doar prin mostenire)

 

 

Clase in afara pachetului

X

 

 

 

Aceast topic este important pentru testul SCJP deoarece daca nu se citeste cu atentie intrebarea exista riscul sa nu observi un modificator de acces de tip private sau default care va ascunde membrii unei clase (aribute sau metode) sau va genera eroare de compilare:

  • o clasa are acces intotdeauna la propriile atribute si metode, indiferent de modificatorul de acces al acestora;
  • membrii protected sunt vizibili in subclase din alte pachete DOAR prin mostenire; asta inseamna ca pot fi accesati doar prin referinta this si nu printr-o referinta de tipul clasei parinte (vezi exemplele de la protected);
  • inainte de a verifica modificatorii de acces ai membrilor (atribute sau metode) unei clase, verifica modificatorii de acces ai clasei (default or public – Tutorial Java SCJP – #13 Packages and Class modificator de access);
  • daca clasa NU este vizibila, atunci nici membrii ei NU sunt, chiar daca sunt definiti public;

Deexemplu, daca clasa ClassD este definita default in pachetul main:

package main;

public class Main {
    public static void main(String[] args) {
    }
}

//clasa default in pachetul main
class ClassD{
    public int atributPublic;
}

atunci in clasa ClassC din pachetul other, clasa ClassD NU este vizibila si deci nici atributele sale publice:

package other;  //alt pachet

public class ClassC {
    public static void faCeva(){

        //eroare de compilare
        ClassD ref = new ClassD();  //cannot find symbol ClassD
    }
}

Acest topic face parte dintr-un tutorial Java 6 accesibil prin Tutorial Java 6 – Continut.