IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 10 - Gettery a settery v Javě

V předešlém cvičení, Řešené úlohy k 9. lekci OOP v Javě, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

Dnes se v tutoriálu podíváme na tzv. gettery a settery.

Gettery a settery

Velmi často se nám stává, že chceme mít kontrolu nad změnami nějakého atributu objektu zvenčí. Budeme chtít atribut nastavit jako read-only (pouze pro čtení) nebo reagovat na jeho změny. Založme si nový projekt s názvem např. GetSet a vytvořme následující třídu Student, která bude reprezentovat studenta v nějakém informačním systému:

class Student {
    public String jmeno;
    public boolean muz;
    public int vek;
    public boolean plnolety;

    public Student(String jmeno, boolean muz, int vek) {
        this.jmeno = jmeno;
        this.muz = muz;
        this.vek = vek;
        plnolety = true;
        if (vek < 18) {
            plnolety = false;
        }
    }

    @Override
    public String toString() {
        String jsemPlnolety = "jsem";
        if (!plnolety) {
            jsemPlnolety = "nejsem";
        }
        String pohlavi = "muž";
        if (!muz) {
            pohlavi = "žena";
        }
        return String.format("Jsem %s, %s. Je mi %d let a %s plnoletý.", jmeno, pohlavi, vek, jsemPlnolety);
    }
}

Třída je velmi jednoduchá, student se nějak jmenuje, je nějakého pohlaví a má určitý věk. Podle tohoto věku se nastavuje atribut plnolety pro pohodlnější vyhodnocování plnoletosti na různých místech systému. K uložení pohlaví používáme hodnotu typu boolean, zda je student muž. Konstruktor dle věku určí, zda je student plnoletý. Metoda toString() je navržena pro potřeby tutoriálu tak, aby nám vypsala všechny informace. V reálu by vrátila pravděpodobně jen jméno studenta. Pomocí konstruktoru si nějakého studenta vytvořme:

        Student student = new Student("Pavel Hora", true, 20);
        System.out.println(student);

Výstup:

Konzolová aplikace
Jsem Pavel Hora, muž. Je mi 20 let a jsem plnoletý.

Vše vypadá hezky, ale atributy jsou přístupné jak ke čtení, tak k zápisu. Objekt tedy můžeme rozbít například takto (hovoříme o nekonzistentním vnitřním stavu):

        Student student = new Student("Pavel Hora", true, 20);
        student.vek = 15;
        student.muz = true;
        System.out.println(student);

Výstup:

Konzolová aplikace
Jsem Pavel Hora, muž. Je mi 15 let a jsem plnoletý.

Určitě musíme ošetřit, aby se plnoletost obnovila při změně věku. Když se zamyslíme nad ostatními atributy, není nejmenší důvod, abychom taktéž umožňovali modifikovat pohlaví. Bylo by však zároveň vhodné je vystavit ke čtení, nemůžeme je tedy pouze nastavit jako private. V dřívějších dílech seriálu jsme k tomuto účelu používali metody, které sloužily ke čtení privátních atributů. Jejich název jsme volili jako vratVek() a pro nastavení atributu například nastavVek(). V Javě se všechny atributy, se kterými se má pracovat zvenčí, označují jako privátní a pro přístup k nim se definují právě podobné metody. K jejich pojmenování se ustálilo getNazevAtributu() pro čtení a setNazevAtributu() pro zápis. Pokud je atribut typu boolean, jmenuje se getter isNazevAtributu(). Třída by nově vypadala např. takto:

class Student {
    private String jmeno;
    private boolean muz;
    private int vek;
    private boolean plnolety;

    public Student(String jmeno, boolean pohlavi, int vek) {
        this.jmeno = jmeno;
        this.muz = pohlavi;
        setVek(vek);
    }

    public String getJmeno() {
        return jmeno;
    }

    public void setJmeno(String jmeno) {
        this.jmeno = jmeno;
    }

    public boolean isMuz() {
        return muz;
    }

    public int getVek() {
        return vek;
    }

    public void setVek(int vek) {
        this.vek = vek;
        // přehodnocení plnoletosti
        plnolety = vek >= 18;
    }

    public boolean isPlnolety() {
        return plnolety;
    }

    @Override
    public String toString() {
        String jsemPlnolety = "jsem";
        if (!plnolety) {
            jsemPlnolety = "nejsem";
        }
        String pohlavi = "muž";
        if (!muz) {
            pohlavi = "žena";
        }
        return String.format("Jsem %s, %s. Je mi %d let a %s plnoletý.", jmeno, pohlavi, vek, jsemPlnolety);
    }
}

Metody, co hodnoty jen vracejí, jsou velmi jednoduché. Nastavení věku má již nějakou vnitřní logiku, při jeho změně musíme totiž přehodnotit atribut plnolety. Zajistili jsme, že se do proměnných nedá zapisovat jinak, než my chceme. Máme tedy pod kontrolou všechny změny atributů a dokážeme na ně reagovat. Nemůže se stát, že by nám někdo vnitřní stav nekontrolovaně měnil a rozbil. Všimněte si i změny v konstruktoru, kde se nastavuje věk metodou setVek().

Metodám k navrácení hodnoty se říká gettery a metodám pro zápis settery. Pro editaci ostatních atributů bychom udělali jednu metodu editujStudenta(), která by byla podobná konstruktoru.

Otázkou je, jaká je nyní výhoda toho, že je atribut jmeno privátní, když do něj jde zapisovat a lze z něj i číst. Vždyť máme v kódu zbytečně 2 metody, které tam zabírají místo a ještě je to pomalé?

Opravdu jsme to napsali správně, nebo alespoň tak, jak se to běžně dělá. Java před kompilací provádí četné optimalizace a pokud jsou metody tak jednoduché, že pouze vrací hodnotu nebo ji nastavují, metoda se zkompiluje jako přímý přístup do paměti. Jsou tedy stejně rychlé, jako kdybychom pracovali s veřejným atributem (za předpokladu, že setter nebo getter nemá nějakou další logiku).

IDE dokáže gettery a settery automaticky generovat, nemusíme je tedy otrocky opisovat. Stačí na privátní proměnnou kliknout pravým tlačítkem a zvolit položku Refactor -> Encapsulate fields:

  • Automatické generování getterů a setterů v IntelliJ - Objektově orientované programování v Javě

    V dalším dialogu si zaškrtneme, ke kterým atributům chceme vygenerovat gettery a settery. My nebudeme chtít zpřístupnit pro zápis atributy plnolety a muz. Atribut plnolety půjde změnit jen změněním věku studenta. Pohlaví nedává smysl měnit vůbec (pokud by to bylo opravdu někdy potřeba, byla by k tomu nějaká speciální metoda, aby se vyloučila změna chybou v kódu). Dialog potvrdíme:

    Automatické generování getterů a setterů v IntelliJ - Objektově orientované programování v Javě

    Settery pro atributy plnolety a muz ze třídy tedy odstraníme.

  • Automatické generování getterů a setterů v IDE NetBeans - Objektově orientované programování v Javě

    V dalším dialogu si zaškrtneme, ke kterým atributům chceme vygenerovat gettery a ke kterým settery. My nebudeme chtít zpřístupnit pro zápis atributy plnolety a muz. Atribut plnolety půjde změnit jen tak, že změníme věk studenta. Pohlaví nedává smysl měnit vůbec (pokud by to bylo opravdu někdy potřeba, byla by k tomu nějaká speciální metoda, aby se vyloučila změna chybou v kódu). Dialog potvrdíme:

    Automatické generování getterů a setterů v NetBeans IDE - Objektově orientované programování v Javě

Optimalizace před kompilací odstranila rychlostní problém, který by jinak zbytečné volání metod způsobovalo. I zbytečné psaní metod jsme vykompenzovali jejich automatickým generováním. Otázkou zůstává, v čem je psaní metod oproti atributům výhodnější.

Hlavním důvodem je určitá standardizace. Nemusíme přemýšlet nad tím, jestli je daná vlastnost objektu řešena přes getter nebo atribut, na instanci jednoduše vždy voláme metodu začínající slovem get (případně is) pokud chceme vlastnost instance číst, případně metodu začínající set, pokud ji chceme změnit.

Další výhodou je, že když se v budoucnu rozhodneme, že nějaký atribut chceme udělat read-only (pouze pro čtení), jednoduše smažeme setter. Nemusíme vytvářet getter a měnit viditelnost atributu, což by změnilo rozhraní třídy a rozbilo existující kód, který by ji používal.

Gettery a settery tedy budeme odteď používat u všech atributů, které mají být zvenčí přístupné. V našich třídách se téměř nebudou vyskytovat atributy s viditelností public.

Zkusme si nyní ještě spustit kód, který předtím rozbil interní stav objektu:

        Student student = new Student("Pavel Hora", true, 20);
        student.setVek(15);
        // student.setMuz(false); // Tento řádek musíme zakomentovat, jelikož se pohlaví již nedá zvenčí změnit
        System.out.println(student);

Výstup je již v pořádku:

Konzolová aplikace
Jsem Pavel Hora, muž. Je mi 15 let a nejsem plnoletý.

V následujícím kvízu, Kvíz - Dědičnost, statika, gettery a settery v Javě OOP, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 634x (9.02 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Řešené úlohy k 9. lekci OOP v Javě
Všechny články v sekci
Objektově orientované programování v Javě
Přeskočit článek
(nedoporučujeme)
Kvíz - Dědičnost, statika, gettery a settery v Javě OOP
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
436 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity