Pouze tento týden sleva až 80 % na e-learning týkající se C# .NET
Nauč se s námi víc. Využij 50% zdarma na e-learningové kurzy.
C# week

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 nebo reagovat na jeho změny. Založme si nový projekt (název 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 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 s = new Student("Pavel Hora", true, 20);
System.out.println(s);

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 s = new Student("Pavel Hora", true, 20);
s.vek = 15;
s.muz = false;
System.out.println(s);

Výstup:

Konzolová aplikace
Jsem Pavel Hora, žena. Je mi 15 let a jsem plnoletý.
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

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žívaly metody, které sloužily ke čtení privátních atributů. Jejich název jsme volili jako vratVek() a podobně. 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 = true;
        if (vek < 18) {
            plnolety = false;
        }
    }

    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 setter nemá nějakou další logiku).

IDE (NetBeans) 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 Refactor -> Encapsulate fields.

Automatické generování getterů a setterů v NetBeans IDE

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 atribut plnolety a pohlavi. 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

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

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

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

V příští lekci, ArrayList v Javě, si představíme kolekci ArrayList, která je mnohem chytřejší než pole a ve které nejsme omezeni počtem prvků.


 

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 466x (2.83 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ě
Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
23 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi 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

 

 

Komentáře
Zobrazit starší komentáře (68)

Avatar
Adam Czernek
Člen
Avatar
Adam Czernek:9.4.2020 10:44

Nene, "My jsme používali"

 
Odpovědět
9.4.2020 10:44
Avatar
Alesh
Překladatel
Avatar
Odpovídá na Adam Czernek
Alesh:9.4.2020 12:35

Jo, pravda, já četl "se", místo "jsme".

 
Odpovědět
9.4.2020 12:35
Avatar
Ondřej Kozel:22.9.2020 23:22

Ahoj, co když třída obsahuje nějakou veřejnou konstantu? U těch se používání getterů nevyplatí, protože je zbytečné nebo se naopak využívají, aby bylo všechno jednotné?

Díky

 
Odpovědět
22.9.2020 23:22
Avatar
Alesh
Překladatel
Avatar
Odpovídá na Ondřej Kozel
Alesh:27.9.2020 15:07

Gettery a settery se využívají proto, aby se nedalo přímo manipulovat s obsahem proměnné "z venku". U konstanty nic měnit nelze, setter je tedy nesmysl, getter je zbytečný.

 
Odpovědět
27.9.2020 15:07
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:1. dubna 11:13

Jen taková malá poznámečka.
V úvodu tutoriálu by se mohlo i přihlížet na skloňování:) Když už jsi ve všem tak důsledný, tak ti potom může vyjít, i třeba tento text:

Jsem Nataša, žena. Je mi 25 let a jsem plnoletý. //<--- Žena a na konci je "plnoletý" :)

Takže jen jako vsuvku bych tam ještě vložil pro korektnost

String gramatickaPlnoletost = muz ? "plnoletý" : "plnoletá";

Ale je to skutečně jen detail, který nemění nic na podstatě :) Spíše kosmetická úprava tutoriálu.

PS:

Když se zamyslíme nad ostatními atributy, není nejmenší důvod, abychom taktéž umožňovali modifikovat pohlaví

Jooooo, zkus toto vysvětlit všem gender fanatikům v roce 2021 :D:D Podle zvrácených teorií by pohlaví neměl být už boolean, ale pomalu už by to mělo být varchar 2128

Editováno 1. dubna 11:14
Odpovědět
1. dubna 11:13
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:1. dubna 11:19

Menší překlep:

za předpokladu, že setter nebo setter nemá nějakou další logiku

Odpovědět
1. dubna 11:19
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:1. dubna 11:38

A jen bych asi doplnil takové krátké 2 věcné poznámky:

  1. Gettery a Settery se nazývají "PŘÍSTUPOVÉ METODY"
  2. Proč se přístupové metody používají a nepoužívá se přímý přístup k atributům instance/třídy je hlavně ze dvou důvodů.
  • Praktické hledisko: Když se dívám na cizí kód a nebo používám cizí knihovnu, tak se nebudu dívat na vnitřní logiku a nebudu hledat, jak si dotyčný pojmenovává kdejaký atribut, ale podívám se, jaké metody mi vystaví - takže jako zkušený programátor, když používám jinou třídu, tak vím, že když chci něco nastavovat, tak se dívám automaticky po metodách se prefixem "set". To samé, když chci získat nějakou informaci, tak hledám prefix "get/is"
  • Historické hledisko: Ono se těžko vysvětluje a dokazuje případ rozbití kódu na jednom atributu. V podstatě i tento modelový příklad, kterým v tutoriálu "rozbíjíš" kód, tak by se dal také rozbít tím, že právě vystavíš setter i pro pohlaví či pro plnoletost. (což u někoho zbrklého, jako jsem třeba já může bez problémů nastat. Navíc když používám Lombok, tak ani netuším, jestli jde nějak díky tomuto pidi frameworku zamezit, aby se nějaká přístupová metoda nevygenerovala... toď otázka do pléna).

Nicméně dřív se do setter metod rvala i logika (viz třeba teď ten nešťastný případ v metodě setVek(). Není to čisté. Hlavně dnešní frameworky jsou stavěné na tom, že přístupové metody opravdu pouze a jenom vracejí/nastavují hodnotu atributu (nebo v případě objektových datových typů přiřazují nebo vrací referenci na objekt). Nic jiného se u přístupových metod neočekává. Logiku pak řešíme v jiných metodách.
Jenže historicky se logika do setterů pak i rvala. Upustilo se od toho hlavně z toho důvodu, že to bylo neintuitivní. Kupříkladu metoda setXPozice nakonec nejen, že nastavovala x-ovou pozici nějakého souřadnicového systému, ale obsahovala podmínky/cykly a vnitřní logiku, kterou by člověk od metody s takovým názvem skutečně nečekal.
Proto se od toho upustilo, ale konvence přístupových metod zůstala a dneska je využívaná jako přístup, se kterým počítá řada frameworků.

Dřívější "rozbití" kódů, které přístupové metody třeba ošetřovaly, tak ukazuje krásný příklad s geometrickými obrazci.
Dejme tomu, když bychom kreslili domeček. Domeček se bude skládat ze čtverce a trojúhelníku. (čtverec = zdivo, trojúhelník = střecha).
Když nastavíme metodu getDum(), tak vrátíme oba tyto atributy a zamezením přístupu k atributům nehrozí, že by nám třeba někdo místo trojuhelniku nastavil třeba kruh.

Jenže jak říkám, toto bylo dřív, dokud se takto řešila logika v přístupových metodách. Dneska se na to dívá z jiného pohledu.

Odpovědět
1. dubna 11:38
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Odpovídá na Lubor Pešek
Jan Křížek:15. dubna 12:45

Potíž s gender tématikou v ČR (a možná i jinde) je v tom, že anglický výraz gender má stejný překlad do češtiny, jako anglický výraz sex, tedy pohlaví. Zatímco sex označuje pohlaví fyziologické, tak gender má označovat něco, čemu by se více hodil český překlad rod, tedy ženský rod, mužský rod a podobně. Tedy jako vhodné řešení v programování bych přidal navíc atribut rod a potom bych použil list, kde by se dalo vybrat z více možností. A ta kosmetická úprava by se vztahovala spíše k rodu.

 
Odpovědět
15. dubna 12:45
Avatar
Odpovídá na Jan Křížek
Nositelka Změny:25. dubna 22:17

Já bych se na pohlaví úplně vykašlala. Za mě je to úplně jedno, kolik jich je. Bohužel člověk může být něco mezi mužem a ženou, a to i biologicky, nejenom duševně. Nemyslím, že je potřeba zrovna varchar, ale proměnnou boolean muz; považuji za docela sexistickou... Pokud už to pohlaví chceme, vždy by tam měla být alespoň možnost "nechci uvést", když už nic jiného. Ale já bych se nebránila ani možnosti "jiné".

Odpovědět
25. dubna 22:17
j.k.j
Avatar
Alesh
Překladatel
Avatar
Alesh:25. dubna 22:30

proměnnou boolean muz; považuji za docela sexistickou...

:-))
Já myslím, že to chce především používat mozek a neřešit kraviny, učíme se zde programovat a ne diskutovat o zhovadilých trendech dnešní doby. :-) Každej snad chápe ten příklad, jak je to myšleno a jak ten boolean funguje.

 
Odpovědět
25. dubna 22:30
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 78. Zobrazit vše