397 lines
29 KiB
Markdown
397 lines
29 KiB
Markdown
# Třídy a instance (objekty)
|
||
|
||
- Objektové programování
|
||
- Program je dekomponován na objekty (abstrakce objektů z reálného světa), které udržují data a metody, které s daty pracují, pohromadě
|
||
|
||
### Třída, instance, reference
|
||
|
||
- Strukturovaný datový typ
|
||
- Na rozdíl od základních datových typů, které obsahují pouze jednu hodnotu a nejde je dále členit, třída může obsahovat data ve formě proměnných (atributů) obecně různého typu
|
||
- Kromě dat obsahuje metody, které obecně provádějí operace nad těmito daty
|
||
- Třída je šablonou pro tvorbu instancí (objektů)
|
||
- Název třídy začíná velkým počátečním písmenem, každé další slovo víceslovného názvu začíná velkým písmenem
|
||
- U dokumentačního komentáře třídy se uvádí alespoň jedna řádka popisující účel třídy, dále autor třídy a případně verze (s datem poslední úpravy)
|
||
|
||
### Instance (objekt)
|
||
|
||
- Je vytvořena podle konkrétní třídy a nese v sobě konkrétní hodnoty atributů (proměnných)
|
||
- Od jedné třídy může být vytvořeno více instancí, přičemž každá může mít (a typicky má) jinak nastavené atributy
|
||
- Aby bylo možné s atributy a metodami definovanými ve třídě pracovat, je NUTNÉ vytvořit její instanci (neplatí při použití klíčového slova ```static```)
|
||
- Tím se vytvoří místo v paměti pro tuto instanci, do kterého se mimo jiné uloží hodnoty jednotlivých atributů
|
||
- Rozdíl oproti základním datovým typům, kdy se místo v paměti vytvořilo v okamžiku deklarace proměnné (tj. v okamžiku provedení řádky ```int i;``` se vytvořilo místo v paměti o velikosti 4 byty pro uložení celého čísla)
|
||
- Reference
|
||
- Abychom mohli pracovat s instancí a jejími atributy a metodami, potřebujeme na ní referenci
|
||
- Reference (referenční proměnná) ukazuje na místo v paměti, kde je uložena konkrétní instance
|
||
|
||
#### Deklarace referenční proměnné a vytvoření instance
|
||
|
||
- Referenční proměnná se deklaruje stejně jako proměnná základního datového typu, tj. názevTypu názevProměnné;
|
||
- ```názevTypu``` je název třídy,
|
||
- ```názevProměnné``` je název referenční proměnné
|
||
- Pouhou deklarací referenční proměnné ale instance třídy nevznikne
|
||
- Po deklaraci (bez inicializace) je referenční proměnná „prázdná“ – není vytvořeno místo v paměti pro instanci a sama referenční proměnná tedy na nic neukazuje
|
||
- POZOR! – Pokud se jedná o lokální proměnnou (tj., proměnnou deklarovanou uvnitř metody), je vhodné inicializovat referenční proměnnou hodnotou null
|
||
- Hodnota ```null``` (klíčové slovo) explicitně říká, že reference neodkazuje (zatím) na žádnou instanci
|
||
- Pokud tuto inicializaci neprovedete, hodnota lokální referenční proměnné není definována a při pokusu o její čtení dojde k chybě (už při překladu programu)
|
||
- Vytvoření instance
|
||
- Instance se vytvoří pomocí operátoru new (klíčové slovo) a přiřadí se do připravené referenční proměnné
|
||
- ```referenčníProměnná = new Třída();```
|
||
- Referenční proměnná musí být stejného typu jako vytvářená instance (tj. ```Třída```)
|
||
- Nebo typu předka třídy nebo rozhraní implementovaného třídou (viz předměty KIV/PPA2 a KIV/OOP)
|
||
|
||
#### Přístup k atributům a metodám instance
|
||
|
||
- K jednotlivým atributům (proměnným) a metodám instance přistupujeme přes referenční proměnnou, která na instanci ukazuje
|
||
- Používá se tečková notace
|
||
- ```referenčníProměnná.proměnnáInstance```
|
||
- Do proměnných (pokud jsou viditelné) lze zapisovat hodnoty a lze je i číst
|
||
- ```referenčníProměnná.metodaInstance()```
|
||
- Metody lze volat (pokud jsou viditelné)
|
||
|
||
#### Práce s referenčními proměnnými a instancemi
|
||
|
||
- Do referenčních proměnných lze přiřazovat nové instance i jiné referenční proměnné
|
||
- Na jednu instanci může ukazovat více referenčních proměnných
|
||
- Pokud už nějakou instanci nebudeme používat, můžeme do referenční proměnné explicitně přiřadit hodnotu ```null```
|
||
- Např. ```pocatek = null;```
|
||
- Tím ztratíme referenci na instanci a Garbage Collector ji časem smaže a uvolní tím paměť, kterou instance zabírá
|
||
- V Javě neexistuje příkaz pro explicitní smazání instance (a tím pádem „ruční“ uvolnění paměti)
|
||
- POZOR! – Pokud má referenční proměnná hodnotu ```null``` (tj. neukazuje na žádnou instanci) nelze přes tuto proměnnou přistupovat k atributům a metodám instance (protože tam žádná instance není)
|
||
- Pokus o přístup vede k chybě ```NullPointerException``` za běhu programu (nikoliv při překladu)
|
||
- Pokud se může stát (v závislosti na předchozím kódu), že referenční proměnná může být ```null```, nebo může ukazovat na instanci, je vhodné před přístupem k proměnným a metodám instance otestovat, zda je referenční proměnná různá od ```null``` – např. ```if (pocatek != null)```
|
||
|
||
### Atributy (proměnné) instance
|
||
|
||
- Protože třídy jsou abstrakce objektů z reálného světa, atributy typicky odpovídají vlastnostem těchto objektů
|
||
- Jako atributy jsou reprezentovány pouze ty vlastnosti, které jsou důležité z hlediska výpočtu (funkce programu)
|
||
- Každá instance může mít (a typicky má) v atributech uloženy jiné hodnoty
|
||
- Atributy (proměnné) instance jsou deklarované uvnitř třídy ale MIMO metody
|
||
- V deklaraci NEMAJÍ uvedeno klíčové slovo ```static```
|
||
- Naprostá většina proměnných v dosavadních programech byla definována uvnitř metod (hlavně ```main()```) a jednalo se tedy o lokální proměnné
|
||
- Pokud byly dosud proměnné deklarované vně metod, jednalo se o statické proměnné třídy (s klíčovým slovem ```static``` – např. používané deklarace ```Scanner```u pro čtení z klávesnice)
|
||
- Dokumentační komentáře jsou typicky jednořádkové a stručně popisují účel proměnné
|
||
- Atributy se typicky deklarují na začátku třídy (před všemi metodami)
|
||
- Kvůli přehlednosti
|
||
- Atribut má viditelnost (je použitelný) přes celou třídu (i před místem deklarace), podobně jako metody
|
||
- Atributy (proměnné) instance mohou být libovolného datového typu (primitivní datový typ, třídy nebo pole) - Není žádné omezení
|
||
- Implicitní inicializace atributů (proměnných) instance
|
||
- U lokálních proměnných (deklarovaných uvnitř metod) bylo doporučeno provést inicializaci hned při deklaraci (např. ```int i = 0;```), aby se nestalo, že se pokusíme číst z proměnné její hodnotu, která ale nebyla nastavená
|
||
- U atributů (proměnných) instance to není nutné, protože jsou automaticky (implicitně) inicializovány na ```0, 0.0, false``` nebo ```null```, v závislosti na datovém typu
|
||
- Doplnit explicitní inicializaci je možné, ale není to nutné ani vhodné
|
||
|
||
#### Konstanty instance
|
||
|
||
- Ve třídě je možné definovat i konstanty instance
|
||
- Stejně jako pro lokální konstanty a statické konstanty třídy je nutné přidat klíčové slovo ```final```
|
||
- ```final datovýTyp JMÉNO_KONSTANTY = hodnota; ```
|
||
- V deklaraci chybí klíčové slovo ```static```
|
||
- Např. ```final int MAXIMALNI_SIRKA = 1280;```
|
||
- Hodnota konstanty instance nemusí být, stejně jako lokální konstanty, nastavena při deklaraci, ale může být **nastavena později** – u **konstanty instance** to však lze provést **pouze v konstruktoru**
|
||
- Vždy však lze **hodnota konstanty nastavit pouze jednou**
|
||
- Mnohem častěji se využívají statické konstanty třídy
|
||
|
||
### Metody instance
|
||
|
||
- Metody instance představují **operace nad atributy instance**
|
||
- Platí pro ně téměř stejná pravidla, jako pro statické metody třídy
|
||
|
||
#### Deklarace metody instance
|
||
|
||
- Deklarace se liší od dosud probraných statických metod třídy pouze chybějícím klíčovým slovem ```static``` v hlavičce metody
|
||
- ```přístupovéPrávo návratováHodnota název(parametry)```
|
||
- Např. ```public double urciVzdalenost(Bod2D b)```
|
||
|
||
#### Volání metod instance
|
||
|
||
- Pokud voláme metodu instance ve stejné třídě, v jaké je deklarována (tj. voláme ji z jiné metody téže třídy), voláme ji pouze jejím jménem a hodnotami parametrů
|
||
- ``metoda(parametry)``
|
||
- Stejné jako u statických metod třídy
|
||
- Např. ```int mocnina = naDruhou(x);```
|
||
- Pokud použijeme metodu vně třídy, ve které je deklarována, musíme před název metody přidat název referenční proměnné ukazující na instanci, nad níž chceme metodu zavolat
|
||
- ```referenčníProměnná.metoda(parametry);```
|
||
- Na rozdíl od statické metody třídy, kdy se používá název třídy
|
||
|
||
### Metody a atributy instance a třídy
|
||
|
||
- Z předchozích kapitol vyplývá, že existují dva druhy metod a dva druhy atributů
|
||
- Metody a atributy (proměnné) instance
|
||
- (Statické) metody a atributy (proměnné) třídy
|
||
|
||
#### Porovnání vlastností metod a atributů instance a třídy
|
||
|
||
- Metody a atributy (proměnné) **instance** (bez ```static```)
|
||
- Každá instance má vlastní hodnoty atributů (proměnných)
|
||
- K proměnným instance se přistupuje přes konkrétní referenční proměnnou ukazující na konkrétní instanci
|
||
- Metody instance se vně své třídy (kde jsou deklarovány) volají nad konkrétní referenční proměnnou ukazující na konkrétní instanci
|
||
- Metody instance mohou uvnitř své třídy volat jiné metody instance i metody třídy a přistupovat k proměnným instance i třídy
|
||
- Při správném objektovém návrhu je to naprostá většina atributů a metod
|
||
- Metody a atributy (proměnné) **třídy** (se ```static```)
|
||
- Každá proměnná třídy má jen jedno paměťové místo a může tak mít jen jednu hodnotu, bez ohledu na to, kolik instancí třídy existuje
|
||
- Paměťové místo pro proměnnou třídy existuje, i když žádná instance ještě neexistuje
|
||
- K proměnným třídy se vně jejich třídy přistupuje přes název třídy
|
||
- Metody třídy se vně své třídy volají nad názvem třídy
|
||
- Metody třídy mohou uvnitř své třídy volat pouze metody třídy a přistupovat pouze k proměnným třídy (metody a proměnné instance deklarované v téže třídě, tj. bez ```static```, jsou pro ně nepřístupné)
|
||
- Při správném objektovém návrhu jich není mnoho
|
||
- Výjimkou jsou konstanty třídy, které jsou podstatně častější než konstanty instance
|
||
|
||
#### Použití metod a atributů (proměnných) instance
|
||
|
||
- Atributy instance obsahují data konkrétní instance třídy
|
||
- Metody instance provádějí operace nad těmito konkrétními daty
|
||
- Díky tomu, že metody instance mají přístup k atributům instance přímo, tato data se nemusí předávat (a nepředávají) jako parametry metod
|
||
- Metody instance jsou poměrně často bez parametrů, protože většinou pracují s proměnnými instance, ke kterým mají přímý přístup (aniž by musely být předávány jako parametry metody)
|
||
- Pokud v programu od třídy vytvářím instanci či instance, většina atributů a metod bude instance, nikoliv třídy
|
||
- Výjimku tvoří konstanty instance, které se v programech používají minimálně
|
||
|
||
#### Použití metod a proměnných třídy
|
||
|
||
- Použití konstant třídy
|
||
- Konstanty v dané třídě jsou ve většině případů stejné pro všechny instance => **není vhodné používat konstanty instance**
|
||
- **Konstanta třídy** zabírá **pouze jedno paměťové místo** (na rozdíl od konstanty instance, kde je zabráno tolik paměťových míst, kolik je instancí)
|
||
- Pro získání hodnoty konstanty třídy se nevytváří instance, přistupuje se k ní přes název třídy (např. ```Math.PI```)
|
||
- Uvnitř třídy není název třídy nutný
|
||
- Konstanty mají obvykle přístupové právo ```public```
|
||
- Konstantě třídy lze přiřadit hodnota pouze přímo v deklaraci, není možné ji inicializovat později
|
||
- Použití statické konstanty třídy je vidět např. na Obr. 13.2
|
||
|
||
- Použití proměnných třídy
|
||
- Málo časté
|
||
- Hodí se, pokud potřebujeme, aby byla proměnná jen jedna pro všechny instance
|
||
- Např. doporučené použití třídy ```Scanner``` pro čtení ze standardního vstupu
|
||
- ```public static Scanner sc;```
|
||
- Aby ```Scanner``` fungoval správně na standardní vstup, je potřeba mít jen jeden v celém programu. Tento požadavek splňuje právě statická proměnná ```sc```, přes kterou pak lze provádět čtení kdekoliv v programu
|
||
- Do proměnné ```sc``` se přiřadí instance hned na začátku metody ```main()``` a tato instance se pak používá pro veškeré čtení
|
||
|
||
- Použití metod třídy
|
||
- Vstupní bod programu – metoda ```main()``` – je metoda třídy (statická)
|
||
- To vychází z toho, že na začátku programu není k dispozici instance žádné třídy, a tedy nemůže být spuštěná metoda instance
|
||
- Pokud potřebuji pomocnou metodu, kterou volám v metodě ```main()```, musí to být rovněž metoda třídy (statická)
|
||
- Zde stojí za zvážení, jestli není lepší v metodě ```main()``` vytvořit instanci a nad ní pak volat libovolné metody instance
|
||
|
||
- Metody, u kterých se nevyplatí vytvářet instanci
|
||
- Je mnoho metod, které realizují nějaký výpočet, ke kterému nepotřebují instanční proměnné ani jiné vlastnosti instance (např. matematické výpočty – metody třídy ```Math```)
|
||
- U takových metod je vhodné, aby byly metody třídy (statické), protože se nemusí vytvářet instance a volají se přímo nad názvem třídy
|
||
- Více takových metod může být deklarováno v tzv. utility třídě
|
||
- Volání je pak možné z jakékoliv metody (třídy či instance)
|
||
|
||
#### Mechanizmus předání referenčních parametrů metod
|
||
|
||
- Metody instance i statické metody třídy mají stejný mechanizmus předávání hodnot parametrů metod
|
||
- Hodnoty parametrů se předávají hodnotou
|
||
- Platí jak pro parametry primitivních datových typů, tak i referencí (typu třídy, ukazujících na instance)
|
||
- Stejný mechanizmus má ale různé důsledky
|
||
- Pro primitivní datové typy se změna hodnoty formálního parametru uvnitř metody neprojeví vně metody (protože hodnota parametru je pouze kopií)
|
||
- Obsah referenční proměnné je však pouze odkaz ukazující na instanci (na rozdíl od proměnné primitivního datového typu, která obsahuje hodnotu přímo, např. celé číslo)
|
||
- Pokud překopírujeme odkaz, bude pořád ukazovat na stejnou instanci => změny provedené v této instanci SE PROJEVÍ i vně metody
|
||
|
||
### Konstruktor
|
||
|
||
- Při vytváření instance třídy operátorem ```new``` je vhodné nastavit počáteční hodnoty atributů této instance (objektu) – pro to slouží tzv. konstruktor
|
||
- Konstruktor
|
||
- Speciální metoda (instance) pro inicializaci objektu
|
||
- Musí se jmenovat stejně jako třída (včetně velikosti písmen)
|
||
- Nemá žádnou návratovou hodnotu (ani ```void```)
|
||
- Podle toho se pozná od ostatních metod (a podle názvu jako třída
|
||
- Při vytváření instance za ```new``` ve skutečnosti voláme konstruktor
|
||
- Protože se jmenuje stejně jako třída, vypadá to, že uvádíme třídu
|
||
- Konstruktor může být bez parametru, nebo může mít „libovolné“ množství a typ parametrů (jako běžná metoda)
|
||
- Konstruktor nemusí být ve třídě explicitně uveden, ale pokud je, typicky obsahuje inicializaci atributů instance
|
||
- Často s předáním hodnot atributů pomocí formálních parametrů konstruktoru
|
||
- Inicializace atributů nemusí být jen hodnotami formálních parametrů, mohou se např. pouze připravovat složitější datové struktury pro další výpočty
|
||
- Konstruktor může být (a často bývá) přetížen
|
||
- Umožňuje různou inicializaci atributů instance
|
||
|
||
#### Proměnná ```this```
|
||
|
||
- V konstruktoru (ale i setrech a dalších metodách) se typicky využívá speciální referenční proměnná ```this```
|
||
- Referenční proměnná ```this```
|
||
- Je dostupná v každé instanci a ukazuje na „tuto“ instanci (tj. na sebe sama)
|
||
- Všechny metody instance volané uvnitř své třídy (tj. z jiných metod instance, bez uvedení referenční proměnné, nad kterou jsou volány) jsou implicitně volány nad proměnnou ```this```, to samé platí pro atributy instance
|
||
- Díky tomu je možné používat metody a atributy instance uvnitř jejich třídy bez uvedení instance (implicitně se použije ```this```)
|
||
- Explicitní použití ```this``` umožňuje přístup k atributům instance, pokud jsou zastíněny lokální proměnnou nebo parametrem metody/konstruktoru se stejným názvem
|
||
- Parametry konstruktoru sloužící pro předání počátečních hodnot atributů instance se typicky jmenují stejně
|
||
- Díky ```this``` není nutné vymýšlet jiné názvy formálních parametrů metod/konstruktorů
|
||
- Explicitní uvedení ```this``` je možné u metod a atributů instance vždy (i když nedochází k zastínění), ale není to nutné ani příliš vhodné
|
||
- přetížení konstruktoru
|
||
- Při přetěžování konstruktoru je možné volat jiný konstruktor téže třídy
|
||
- Volání jiného konstruktoru musí být první příkaz v konstruktoru
|
||
- Volá se pomocí ```this(parametry);```, nikoliv jménem konstruktoru
|
||
- Není třeba opakovat kód konstruktoru => používá se běžně
|
||
|
||
#### Implicitní konstruktor
|
||
|
||
- Pokud ve třídě není žádný konstruktor uveden volá se při vytváření nové instance implicitní konstruktor bez parametrů
|
||
- Tento konstruktor bez parametrů zajistí vytvoření instance v paměti
|
||
- Atributy instance jsou implicitně inicializovány na ``0, 0.0, false`` nebo ```null``` podle datového typu
|
||
- POZOR! – Pokud do třídy přidáme libovolný explicitní konstruktor, implicitní konstruktor nebude vytvořen!
|
||
- Pokud potřebujeme i konstruktor bez parametrů jako doplněk k dalším konstruktorům, musíme ho rovněž explicitně napsat
|
||
- Pak je možné použít konstruktor bez parametrů (ale nejedná se o implicitní konstruktor, protože je ve třídě přímo napsaný)
|
||
|
||
### Zapouzdření a přístupová práva
|
||
|
||
- Atributy mohou být přístupné z vnějšku třídy
|
||
- Tento postup není vhodný, protože umožňuje změnu atributů bez jakékoliv kontroly, což umožňuje mj. zadat neplatné hodnoty
|
||
- **Zapouzdření** (encapsulation)
|
||
- Atributy objektu jsou **skryté před vnějšími vlivy** pomocí **přístupových práv**
|
||
- Pokud je potřeba změnit nastavení atributů, provádí se to prostřednictvím metod, které mohou obsahovat kontroly – tzv. ```setry```
|
||
- Tyto metody by měly existovat pouze pro atributy, u kterých chceme jejich změnu z vnějšku třídy umožnit
|
||
- Pokud je potřeba získat hodnoty atributů, jsou zpřístupněny metodami nazvanými ```getry```
|
||
- Tyto metody by měly existovat pouze pro atributy, jejichž hodnota má být přístupná z vnějšku třídy
|
||
- I metody mohou mít nastavená přístupová práva tak, aby je nebylo možné volat z vnějšku třídy
|
||
- Typicky pomocné metody
|
||
|
||
#### Přístupová práva
|
||
|
||
- Přístupová práva určují, odkud lze k dané metodě nebo atributu přistoupit
|
||
- Klíčová slova určující přístupová práva se píší na začátek deklarace
|
||
- U atributů před datový typ
|
||
- Např. ```private int pocetClenu;```
|
||
- U metod před návratovou hodnotu nebo ```void```
|
||
- Např. ```public int naDruhou(int x)```
|
||
- Přístupová práva (od nejméně po nejvíce restriktivní)
|
||
- ```public```
|
||
- Metoda/atribut je přístupný odkudkoliv (ze stejné třídy, z jiné třídy stejného balíku, z jiné třídy jiného balíku)
|
||
- Typicky se používá pro metody
|
||
- ```protected```
|
||
- Metoda/atribut je přístupný ze stejné třídy, z jiné třídy stejného balíku a z potomka třídy (viz předmět KIV/OOP)
|
||
- Neuvedeno (přístupové právo není explicitně uvedeno)
|
||
- Metoda/atribut je přístupný ze stejné třídy a z jiné třídy stejného balíku
|
||
- ```private```
|
||
- Metoda/atribut je přístupný pouze ze stejné třídy
|
||
- Typicky se používá pro atributy
|
||
- Přístupová práva u třídy (a také rozhraní – viz předměty KIV/OOP a KIV/PPA2)
|
||
- ```public```
|
||
- Třída musí být v souboru odpovídající názvu třídy
|
||
- Neuvedeno
|
||
- Třída může být v jiném souboru, který neodpovídá názvu třídy
|
||
- Více tříd pak může být v jednom souboru, ale maximálně jedna může být ```public``` (a její název pak odpovídá názvu souboru)
|
||
- Pak ale není viditelná z jiného balíku => nepoužívat
|
||
- Jiná přístupová práva pro třídy možná nejsou
|
||
|
||
#### Getry a setry
|
||
|
||
- Metody pro přístup k atributům
|
||
- Getry začínají slovem ```get``` (anglicky „získat“), v případě atributu typu boolean slovem ```is``` (anglicky „je“)
|
||
- Setry začínají slovem ```set``` (anglicky „nastavit“)
|
||
- Slova ```get``` a ```set``` se používají, i když píšeme zdrojový kód česky
|
||
- Je to konvence pojmenování, která se dodržuje
|
||
- Jinak jsou to běžné metody
|
||
- Getry
|
||
- Hlavička přesně daná pro daný atribut
|
||
- ```public datovýTypAtributu getAtribut()```
|
||
- ```public boolean isAtribut()```
|
||
- Např. ```public int getX()```
|
||
- Např. ```public boolean isPrazdny()```
|
||
- Vrací hodnotu atributu, typicky obsahují jedinou řádku s příkazem ```return```
|
||
- Setry
|
||
- Hlavička přesně daná pro daný atribut
|
||
- ```public void setAtribut(datovýTypAtributu atribut)```
|
||
- Např. ```public void setX(int x)```
|
||
- Nastaví hodnotu atributu
|
||
- Obsahuje přiřazení hodnoty do atributu předané přes formální parametr setru
|
||
- Typicky se používá referenční proměnná ```this``` jako v konstruktoru
|
||
- Typicky by měl obsahovat **kontrolu**, **zda je hodnota formálního parametru platná** (přípustná)
|
||
- POZOR! – Nastavit hodnotu pouze, pokud je platná, a jinak neudělat nic není nejšťastnější řešení – **reálně se řeší pomocí výjimek**
|
||
- Pokud tuto **kontrolu neobsahuje**, pak se vlastně o **zapouzdření nejedná**, protože si můžeme z vnějšku třídy dělat s atributem, co chceme (byť prostřednictvím getru a setru)
|
||
- Pokud tuto kontrolu dělá, **měl by být setr použit i v konstruktoru** místo přímého přiřazení
|
||
- Přiřazení je bez kontroly, což umožňuje zadat neplatnou hodnotu přes formální parametry konstruktoru
|
||
- Běžné metody instance (ne getry a setry) mohou měnit více atributů najednou, čímž vyjádří jednu změnu stavu instance
|
||
- Pokud jsou na sobě atributy závislé a neměly by se měnit každý zvlášť, pak by pro ně neměly existovat setry a místo toho by měla existovat metoda měnící konzistentně všechny závislé atributy najednou
|
||
|
||
### Textová reprezentace objektu
|
||
|
||
- Objekty (instance), mohou být velmi komplikované (obsahovat mnoho různých atributů), často je ale **potřeba získat textovou reprezentaci** objektu (ve formě řetězce – ```String```)
|
||
- **Pro výpis objektu** do příkazové řádky – velmi často během ladění programu
|
||
- **Pro zobrazení objektu** např. v seznamu v grafickém uživatelském prostředí (GUI)
|
||
- Jsou i další použití
|
||
- Vypisování hodnot jednotlivých atributů ručně je zdlouhavé, pokud je atributů více, a kód pro výpis je navíc v jiné třídě => využívá se metoda ```toString()```
|
||
|
||
#### Metoda toString()
|
||
|
||
- Metoda vracející textovou reprezentaci objektu (instance)
|
||
- Hlavička metody ```public String toString()```
|
||
- Tato metoda je implicitně v každé instanci (je zděděna od třídy ```Object``` – viz předmět KIV/OOP)
|
||
- Vrací řetězec popisující danou instanci
|
||
- Metoda pouze VRACÍ řetězec, sama ho NEVYPISUJE
|
||
Tato metoda se volá, pokud chceme objekt (instanci) vypsat pomocí metody ```System.out.println()```
|
||
- **Implicitní implementace**
|
||
- Vrací řetězec obsahující název třídy, zavináč a číslo určující konkrétní instanci
|
||
- Např. ```Bod2D3@15db9742```
|
||
- Neobsahuje informace o stavu třídy (např. hodnoty atributů)
|
||
- **Vlastní implementace**
|
||
- Implicitní metodu lze překrýt **vlastní implementací**
|
||
- Stačí ve třídě vytvořit **metodu se stejnou hlavičkou**
|
||
- Před metodu je vhodné napsat ```@Override``` indikující, že **metoda je překryta** (overridden)
|
||
- Není to nutné, ale např. Eclipse tuto entitu doplní automaticky, pokud necháme metodu ```toString()``` vygenerovat
|
||
- Bližší informace viz předmět KIV/OOP
|
||
- Metoda musí vracet řetězec, ale ten může obsahovat cokoliv
|
||
- Typicky obsahuje hodnoty atributů (při ladění programu), ale záleží na tom, na co chceme textovou reprezentaci třídy použít
|
||
- Příklad typické metody ```toString()```
|
||
|
||
### Porovnání objektů
|
||
|
||
- Objekty (instance) obecně nejsou uspořádané jako základní datové typy, operátory ```„>“, „>=“, „<“, „<=“``` tedy nelze použít
|
||
- Lze však použít porovnání na rovnost (operátor ```„==“```) a také různost (operátor ```„!=“```)
|
||
- POZOR! – Má jiný než očekávaný význam
|
||
- Výsledkem porovnání je **true**, **pokud se jedná o stejnou instanci** (tj. porovnávané referenční proměnné odkazují na stejnou instanci). **Pokud se nejedná o stejnou instanci**, je výsledkem porovnání **false**
|
||
- I když mají **dvě instance stejné třídy stejné hodnoty** všech atributů, výsledek je **false**
|
||
- Často je ale potřeba zjistit, zda jsou objekty shodné podle hodnot atributů (některých nebo všech)
|
||
- Lze dělat ručně porovnáváním jednotlivých atributů, ale pro více atributů zdlouhavé a kód pro porovnání je v jiné třídě => využívá se metoda ```equals()```
|
||
|
||
#### Metoda equals()
|
||
|
||
- Metoda slouží **k porovnání objektu** (instance) **s objektem stejné třídy**
|
||
- Hlavička metody ```public boolean equals(Object o)```
|
||
- Tato metoda je implicitně v každé instanci (je zděděna od třídy ```Object``` – viz předmět KIV/OOP)
|
||
- Stejně jako metoda ```toString()```
|
||
- Metoda vrací ```true```, pokud jsou instance shodné a ```false```, pokud jsou instance rozdílné
|
||
- **Co je shodné a rozdílné, určuje kód metody**
|
||
- Typicky **se porovnávají hodnoty atributů**
|
||
- **Implicitní implementace**
|
||
- Chová se stejně jako operátor „```==```“
|
||
- Vrací **true** pouze v případě, že je **stejná instance**
|
||
- **Explicitní implementace**
|
||
- Implicitní metodu lze překrýt **vlastní implementací**
|
||
- Stačí ve třídě vytvořit metodu se stejnou hlavičkou
|
||
- Před metodu je vhodné napsat ```@Override``` indikující, že metoda je překryta (overridden)
|
||
- Existují doporučení, jak má kód metody ```equals()``` vypadat (viz předmět KIV/OOP)
|
||
- Porovnávaná instance je v parametru, který je typu (třídy) ```Object```
|
||
- Aby bylo možné číst atributy porovnávané instance, je potřeba proměnnou explicitně přetypovat na typ třídy naší instance
|
||
- Přetypování se zapisuje stejně jako u základních datových typů (název třídy v kulaté závorce)
|
||
- Při pokusu o přetypování na nesprávný typ dojde k chybě za běhu programu
|
||
- Pak je možné porovnávat jednotlivé atributy
|
||
- Příklad implementace metody ```equals()```
|
||
|
||
### Výčtový typ
|
||
|
||
- Výčtový typ v Javě je sofistikovanější řešení pojmenovaných konstant
|
||
|
||
#### Základní použití výčtového typu
|
||
|
||
- Základní použití výčtového typu se hodí v případě, kdy
|
||
- Máme více konstant, které spolu souvisí
|
||
- Jejich hodnota je irelevantní
|
||
- Deklarace výčtového typu
|
||
- Deklaruje se podobně jako třída, místo klíčového slova ```class``` se použije klíčové slovo ```enum```
|
||
- Pravidla pojmenování jsou stejná jako pro třídu – počáteční písmeno velké, počáteční písmena všech dalších slov víceslovného názvu velká
|
||
- Pokud je označen přístupovým právem ```public```, musí být v samostatném souboru, jehož název odpovídá názvu výčtového typu
|
||
- Na začátku obsahuje konstanty, což jsou jednotlivé hodnoty výčtového typu
|
||
- Pravidla pojmenování stejná jako pro konstanty – všechna písmena velká, oddělovač slov ve víceslovném názvu je podtržítko
|
||
- Konstanty jsou odděleny čárkami
|
||
- Použití výčtového typu
|
||
- Výčtový typ můžeme využít pro deklarování libovolné proměnné (lokální, instance, třídy), jako návratovou hodnotu metody, atd. – stejně jako jakýkoliv jiný datový typ (základní, třída, pole)
|
||
- Do proměnné výčtového typu lze přiřadit pouze jednu z konstant definovaných v deklaraci výčtového typu nebo hodnotu ```null```
|
||
- Při použití konstanty je třeba použít název výčtového typu
|
||
- ```VýčtovýTyp.KONSTANTA```
|
||
- Podobně jako u konstant třídy
|
||
- Hodnoty výčtového typu lze porovnávat operátorem „```==```“ s očekávaným výsledkem (na rozdíl od instancí třídy)
|
||
- Hodnoty výčtového typu lze přímo vypsat
|
||
- Vypíše se přímo název konkrétní konstanty
|
||
|
||
#### Pokročilé použití výčtového typu
|
||
|
||
- Výčtový typ má větší možnosti než bylo popsáno
|
||
- Může obsahovat proměnné a metody, které se pak vážou k jednotlivým hodnotám výčtového typu
|
||
- Např. u typu ```HodnotaKaret``` by bylo možné u každé hodnoty uvést bodovou hodnotu karet
|
||
- Podrobnosti viz předmět KIV/OOP
|
||
|