OBJEKTINIS PROGRAMAVIMAS

Java getteriai ir setteriai

Getteriai ir setteriai yra metodai, kurie kontroliuoja privačių objekto laukų skaitymą bei keitimą. Tai vienas pagrindinių inkapsuliacijos taikymo būdų Java programose.

Kodėl laukus verta slėpti?

Inkapsuliacija saugo objekto vidinę būseną nuo nekontroliuojamo išorinio keitimo. Dažniausiai:

  • klasės atributai deklaruojami su private;
  • reikšmė skaitoma per viešą getterį;
  • reikšmė keičiama per viešą setterį, jei keitimas leidžiamas;
  • setteris gali patikrinti reikšmę prieš ją išsaugodamas.

Getterio ir setterio sukūrimas

public class Knyga {
    private String pavadinimas;

    public String getPavadinimas() {
        return pavadinimas;
    }

    public void setPavadinimas(String naujasPavadinimas) {
        this.pavadinimas = naujasPavadinimas;
    }
}
Konsolės rezultato nėra.

Čia tik aprašyta klasė ir jos metodai. Objektas nesukurtas, metodai neiškviesti, todėl niekas nespausdinama.

  1. Atributas pavadinimas yra private, todėl išorinis kodas jo tiesiogiai nepasiekia.
  2. getPavadinimas() yra getteris – jis grąžina dabartinę atributo reikšmę.
  3. setPavadinimas(...) yra setteris – jis priima naują tekstą.
  4. this.pavadinimas reiškia objekto atributą, o naujasPavadinimas – setterio parametrą.
  5. Klasė pati nusprendžia, kokiais viešais metodais leidžiama skaityti arba keisti jos duomenis.
Getterio ir setterio paskirtis
MetodasPaskirtisRezultatas
getPavadinimas()Perskaityti laukąGrąžina String
setPavadinimas(...)Pakeisti laukąPriima parametrą ir paprastai grąžina void

this.pavadinimas nurodo objekto lauką, o naujasPavadinimas – setterio parametrą.

Tiesioginė prieiga negalima

Kodas už klasės ribų negali tiesiogiai pasiekti private lauko:

Knyga knyga = new Knyga();

knyga.pavadinimas = "Mažasis princas";
System.out.println(knyga.pavadinimas);
Kompiliatoriaus rezultatas

error: pavadinimas has private access in Knyga

  1. Kodas bando tiesiogiai įrašyti reikšmę į knyga.pavadinimas.
  2. Tačiau atributas pavadinimas pažymėtas private.
  3. Todėl jo negalima nei keisti, nei skaityti už Knyga klasės ribų.
  4. Kompiliatorius sustabdo programą, tad įprastos konsolės išvesties nėra.

Vietoje to naudojami klasės pateikti vieši metodai:

public class Main {
    public static void main(String[] args) {
        Knyga knyga = new Knyga();

        knyga.setPavadinimas("Mažasis princas");
        System.out.println(knyga.getPavadinimas());
    }
}
Konsolės rezultatas

Mažasis princas

  1. Setteris setPavadinimas() gauna tekstą Mažasis princas.
  2. Kadangi setteris yra pačios klasės metodas, jis gali pakeisti privatų atributą.
  3. Getteris getPavadinimas() perskaito išsaugotą reikšmę ir ją grąžina.
  4. println() parodo getterio grąžintą pavadinimą.

Duomenų tikrinimas setteryje

Setteris leidžia apsaugoti objekto būseną nuo netinkamų reikšmių. Knygos puslapių skaičius turi būti didesnis už nulį:

public class Knyga {
    private int puslapiuSkaicius;

    public int getPuslapiuSkaicius() {
        return puslapiuSkaicius;
    }

    public void setPuslapiuSkaicius(int naujasSkaicius) {
        if (naujasSkaicius <= 0) {
            System.out.println("Puslapių skaičius turi būti teigiamas");
            return;
        }

        this.puslapiuSkaicius = naujasSkaicius;
    }

    public static void main(String[] args) {
        Knyga knyga = new Knyga();

        knyga.setPuslapiuSkaicius(96);
        System.out.println(knyga.getPuslapiuSkaicius());

        knyga.setPuslapiuSkaicius(-5);
        System.out.println(knyga.getPuslapiuSkaicius());
    }
}
Konsolės rezultatas

96
Puslapių skaičius turi būti teigiamas
96

  1. Pirmasis setterio iškvietimas perduoda tinkamą reikšmę 96.
  2. Sąlyga 96 <= 0 yra klaidinga, todėl atributas sėkmingai pakeičiamas.
  3. Antras iškvietimas perduoda netinkamą reikšmę -5.
  4. Setteris parodo klaidos pranešimą ir su return baigia darbą dar nepakeitęs atributo.
  5. Todėl paskutinis getterio iškvietimas vis dar grąžina ankstesnę tinkamą reikšmę 96.
Viešas laukas tokios kontrolės nesuteiktų.

Bet kuris išorinis kodas galėtų įrašyti, pavyzdžiui, -5 puslapius ir palikti objektą netinkamos būsenos.

Tik skaitymui skirtas laukas

Ne kiekvienam laukui reikia setterio. Jei pateikiamas tik getteris, išorinis kodas reikšmę gali skaityti, bet negali pakeisti:

public class Knyga {
    private final String isbn;

    public Knyga(String isbn) {
        this.isbn = isbn;
    }

    public String getIsbn() {
        return isbn;
    }

    public static void main(String[] args) {
        Knyga knyga = new Knyga("978-609-01-0000-0");
        System.out.println(knyga.getIsbn());
    }
}
Konsolės rezultatas

978-609-01-0000-0

  1. ISBN atributas yra ir private, ir final.
  2. Jo reikšmė suteikiama konstruktoriuje kuriant objektą.
  3. Getteris getIsbn() leidžia išoriniam kodui reikšmę perskaityti.
  4. Setterio nėra, todėl klasė nesiūlo būdo ISBN pakeisti.
  5. final papildomai užtikrina, kad po priskyrimo atributui nebus suteikta kita reikšmė.

boolean getterio pavadinimas

Loginėms savybėms getteris pagal įprastą Java vardų susitarimą dažnai pradedamas is:

public class Knyga {
    private boolean perskaityta;

    public boolean isPerskaityta() {
        return perskaityta;
    }

    public void setPerskaityta(boolean perskaityta) {
        this.perskaityta = perskaityta;
    }

    public static void main(String[] args) {
        Knyga knyga = new Knyga();
        knyga.setPerskaityta(true);
        System.out.println(knyga.isPerskaityta());
    }
}
Konsolės rezultatas

true

  1. Privatus atributas perskaityta pradžioje turi numatytąją reikšmę false.
  2. Setteris setPerskaityta(true) pakeičia jį į true.
  3. Loginio atributo getteris pavadintas isPerskaityta().
  4. Getteris grąžina dabartinę reikšmę, o println() ją parodo konsolėje.

Pavadinimų susitarimai

  • Laukui pavadinimas naudojami getPavadinimas() ir setPavadinimas(...).
  • Pirmoji lauko pavadinimo raidė metodo dalyje rašoma didžioji.
  • boolean getteris dažnai vadinamas isPerskaityta().
  • Setterio parametro tipas turi atitikti lauko tipą.

Ne kiekvienam laukui reikia get ir set

Automatiškai kuriant getterį ir setterį kiekvienam laukui galima susilpninti inkapsuliaciją. Viešink tik tuos veiksmus, kurių iš tikrųjų reikia. Kartais aiškesnis metodas yra perskaitytiPuslapius(10), o ne tiesioginis setPerskaitytaPuslapiu(10), nes jis geriau nusako objekto elgseną.