FAV-ZCU/KIV PPA1/8. Pole.md

217 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pole
- **Strukturovaný datový typ pro uložení více prvků stejného typu**
- Pro uložení více hodnot stejného typu se hodí pole
### Základní práce s (jednorozměrným) polem
- Pole
- Strukturovaný datový typ
- Skládá se z **pevně daného počtu prvků**
- **Je homogenní** všechny prvky v něm uložené jsou stejného typu
- **Počet prvků se stanoví při inicializaci** (vytvoření) pole a pak již **nelze změnit**
- **Počet prvků je délka pole**, která je v **poli kromě prvků rovněž uložená**
- Indexy
- Jednotlivé prvky pole jsou **přístupné pomocí indexů**
- V Javě má index vždy hodnoty 0 až délka pole - 1
#### Deklarace a vytvoření pole
- Pole je podobné třídám a objektům
- V podstatě se jedná o speciální třídu a při inicializaci pole vytváříme její „instanci“ uloženou na haldě
- Je potřeba deklarovat referenční proměnou a vytvořit novou „instanci pole“ operátorem ```new```
- Stejně jako u objektů je možné udělat obojí najednou, nebo nejprve deklarovat referenční proměnou a později vytvořit nové pole
- ```datovýTyp[] proměnná = new datovýTyp[početPrvků];```
- Při vytváření nového pole se udává počet prvků (v hranatých závorkách „[“ a „]“), které bude pole obsahovat
- Typ prvků pole může být libovolný
- Libovolný základní datový typ
- Libovolná třída
- Protože proměnná typu pole je referenční, může být ```null```
- Pokud se jedná o lokální proměnnou a nevytváříme pole hned při deklaraci jeho referenční proměnné, je rozumné inicializovat referenční proměnnou na ```null```
- Pokud se jedná o proměnnou instance nebo třídy, je inicializována na ```null``` implicitně
- Při vytvoření pole jsou jeho jednotlivé prvky implicitně inicializovány na ```0, 0.0, false``` nebo ```null``` podle datového typu pole
- I v případě, že referenční proměnná ukazující na pole je lokální
- Vytvoření pole výčtem hodnot
- Pole je kromě operátoru ```new``` možné vytvořit i výčtem jeho hodnot uvedeným ve složených závorkách ```„{“``` a ```„}“```
- Např. ```int[] fibonacci = {0, 1, 1, 2, 3, 5, 8, 13};```
- Pole má stejné vlastnosti jako pole vytvořené operátorem ```new``` délku pole určí překladač podle počtu prvků
- Často používáno jako vzorová data pro usnadnění ladění, nebo uložení pole konstantních hodnot
- POZOR! Takto definované pole nemá konstantní prvky, **jeho prvky lze libovolně měnit**, např. ```fibonacci[3] = -6;```
- POZOR!
- Samotným výčtem hodnot lze pole vytvořit POUZE PŘI DEKLARACI
- Pokud chceme přiřadit do existující referenční proměnné nové pole výčtem hodnot, musí samotnému výčtu předcházet vytvoření pole operátorem ```new``` bez udání počtu prvků
- proměnná = ```new datovýTyp[] {hodn1, hodn2, …};```
- Např. ```fibonacci = new int[] {1, 1, 2, 3};```
- Konstantní pole
- Použití klíčového slova ```final``` nezajistí, aby prvky pole po prvním přiřazení nešly změnit
- ```final``` pouze zajistí konstantnost referenční proměnné nelze do ní již přiřadit jinou hodnotu (tj. jiné pole)
- Prvky pole, na které ukazuje ```final``` referenční proměnná lze ale měnit bez problémů
- To samé platí pro referenční proměnné a instance tříd hodnoty atributů (proměnných) instance lze měnit, i když je referenční proměnná ukazující na instanci označena jako ```final```
#### Přístup k prvkům pole a jeho délka
- K jednotlivým prvkům pole se přistupuje pomocí indexu
- Index se zapisuje za referenční proměnou do hranatých závorek
- ```proměnná[index]```
- Prvek pole se chová stejně jako proměnná odpovídajícího datového typu
- Lze do něj zapisovat hodnotu
- Lze z něj číst hodnotu
- Např. ```teploty[0] = 17.5;```
- Např. ```double teplota = teploty[0];```
- Délka pole
- Každé pole má v sobě informaci o délce uloženou v proměnné ```length```
- Volá se přes tečkovou notaci stejně jako proměnná instance nad referenční proměnnou pole
- Např. ```int pocetTeplot = teploty.length;```
- První prvek pole má index 0
- ```Např. double prvniTeplota = teploty[0];```
- Poslední prvek pole má index ```pole.length 1```
- Např. ```double posledniTeplota = teploty[teploty.length - 1];```
- Index mimo rozsah pole
- POZOR! Při pokusu o přístup k prvkům se záporným indexem nebo indexem větším nebo rovným délce pole, dojde k chybě za běhu programu (nikoliv při překladu) je vyhozena výjimka ```ArrayIndexOutOfBoundsException```
- Použití pole jako parametr metody
- Pole může být použito jako parametr metody (stejně jako primitivní datový
typ nebo třída)
- POZOR! Stejně jako u tříd a instancí platí, že změny provedené v hodnotách pole předaného do metody jako parametr se projeví vně metody
#### Výpis celého pole, inicializace stejnou hodnotou
- Pro práci s poli existuje utility třída ```java.util.Arrays```
- Obsahuje statické metody (podobně jako třída ```Math```) pro práci s poli
- Výpis celého pole
- Metoda ```Arrays.toString()```
- Převede celé pole na řetězec, který lze následně vypsat např. metodou ```System.out.println();```
- POZOR!
- Sama metoda řetězec pouze vrací, nevypisuje ho
- Podobně jako metoda instance toString() u objektů
- Pokud necháme vypsat pole metodou ```System.out.println()``` přímo (bez metody ```Arrays.toString()```), vypíše se pouze identifikace „instance pole“
- Podobně jako implicitní implementace metody instance ```toString()``` u objektů
- Např. volání ```System.out.println(vektor1);``` vypíše např. [D@1b6d3586 (čísla za „@“ se budou při různých spuštěních lišit)
- Inicializace prvků pole stejnou hodnotou
- Prvky pole jsou při vytvoření implicitně inicializovány na ```0, 0.0, false``` nebo ```null``` podle datového typu pole
- Pokud je potřeba inicializovat pole jinou hodnotou (stejnou pro všechny prvky), je možné využít metodu ```Arrays.fill(pole, hodnota);```
- Např. ```Arrays.fill(ciselnaRada, 1);``` naplní všechny prvky pole ```ciselnaRada``` hodnotou ```1```
- Metoda je překrytá pro pole všech základních datových typů a pole typu ```Object```
- Existuje i varianta s určením počátečního a koncového indexu vyplnění pole ```Arrays.fill(pole, indexOd, indexDo, hodnota);```
Např. ```Arrays.fill(ciselnaRada, 0, 2, 10);``` naplní první dva prvky (**počáteční index je včetně**, **koncový není včetně**) pole ```ciselnaRada``` hodnotou ```10```
#### Použití zápisu ```for - each```
- Pokud nepotřebujeme pracovat s indexem pole a stačí nám postupný přístup ke všem jednotlivým prvkům, je možné použít zkrácený zápis cyklu ```for``` (známý též jako ```for - each```)
- ```for (datovýTyp prvek: pole)```
- Cyklus zaručí, že se dostane na všechny prvky projde se celé pole od začátku do konce
- V každé obrátce cyklu je v proměnné prvek následující prvek pole
- Běžně se používá pro pole (a kolekce viz předmět KIV/PPA2) objektů
#### Pole jako tabulka, přepočet indexů
- Tabulka
- Datová struktura obsahující dvojice klíč a hodnota
- Pro daný klíč můžeme získat hodnotu
- Viz předměty KIV/PPA2 a KIV/PT
- Pole se dá použít jako jednoduchá tabulka
- Index může sloužit jako klíč
- Hodnota prvku pole jako hodnota
- Indexy pole začínají vždy od 0 pokud je potřeba jiný začátek klíčů, je potřeba přepočet
#### Reprezentace množiny polem
- Množina
- Soubor prvků (např. čísel) chápaných jako celek
- Každý prvek může být obsažen v množině maximálně jednou
- Pro reprezentaci množiny lze využít pole typu ```boolean[]```
- Indexy odpovídají prvkům množiny
- Hodnoty prvků pole udávají, zda prvek je přítomný v množině (```true```) nebo není (```false```)
### Pole objektů
- Prvkem pole můžou být kromě základních datových typů i instance
- Použití se nijak neliší, jen je potřeba nezapomenout vytvořit instance jednotlivých prvků, což se u základních datových typů nedělá
#### Deklarace pole objektů a jeho inicializace
- Deklarace a vytvoření pole se neliší od polí základních datových typů
- Je potřeba deklarovat referenční proměnnou a vytvořit novou „instanci pole“ operátorem ```new```
- ```Třída[] proměnná = new Třída[početPrvků];```
- Např. ```Vysledek[] vysledky = new Vysledek[POCET];```
- Opět je možné nejprve deklarovat referenční proměnnou a později vytvořit nové pole
- Jednotlivé prvky referenční proměnné na instance třídy odpovídající typu pole
- Po vytvoření pole jsou všechny implicitně inicializovány na hodnotu ```null```
- POZOR! V tomto okamžiku (po vytvoření pole) tedy jednotlivé instance prvků neexistují dosud nebyly vytvořeny operátorem ```new```
- Vytvoření instancí prvků pole
- Instanci každého prvku je potřeba vytvořit zvlášť, typicky v cyklu ```for```
#### Přístup k prvkům pole a k proměnným a metodám instance prvků
- Přístup k prvkům pole je stejný jako u polí základních datových typů pomocí indexu v hranatých závorkách „[“ a „]“
- Jednotlivé prvky jsou referenční proměnné ukazující na jednotlivé instance
- Přístup k atributům a metodám instance je přes tečkovou notaci použitou nad prvkem pole
### Vícerozměrná pole
- Pole může mít více rozměrů
- Často se využívají dvourozměrná (např. pro uložení matic), ale mohou být i tří a vícerozměrná
- Pole s více než třemi rozměry většinou nemají reálné opodstatnění
- Pro určení požadovaného prvku pole je potřeba více indexů
- Počet odpovídá počtu rozměrů pole
- Vícerozměrné pole jako **pole polí**
- Dvourozměrné pole v Javě je ve skutečnosti jednorozměrné pole referenčních proměnných, kde každá ukazuje na jednorozměrná pole (tj. „řádku“)
- Díky tomu má každé jednorozměrné pole svou délku, kterou je možné zjistit, a dvourozměrné pole ji má též
- Z dvourozměrného pole tak lze zjistit jeho počet řádek i sloupců
- Každé jednorozměrné pole může mít jinou délku
- Trojrozměrné pole v Javě je pak jednorozměrné pole referenčních proměnných, kde každá ukazuje na dvourozměrné pole, atd.
#### Deklarace a vytvoření vícerozměrného pole
- Deklarace referenční proměnné pro vícerozměrné pole je podobná jako pro jednorozměrné
- Pouze obsahuje více prázdných párů hranatých závorek „[]“ jeden pár pro každý rozměr pole
- ```datovýTyp[][]…[] proměnná;```
Např. ```double[][] prvkyMatice;```
- Vytvoření všech rozměrů najednou
- Nejběžnější použití vícerozměrných polí
- Počty prvků ve všech rozměrech pole udány najednou
- V případě dvourozměrného pole má každý řádek stejnou šířku
- Tzv. pravoúhlé pole pole tvoří pravoúhlý obrazec obdélník, kvádr, teserakt, atd.
- ```proměnná = new datovýTyp[počet1][počet2]…[početN];```
- Např. ```prvkyMatice = new double[vyska][sirka];```
- Vytvoření rozměrů postupně
- Počty prvků v jednotlivých rozměrech udány postupně
- Nejprve vytvoříme „vnější“ pole a pak do jeho jednotlivých prvků přiřadíme nové „instance“ „vnitřních“ polí
- V případě dvourozměrného pole může mít každý řádek různou délku
- Pole je „zubaté“
- ```proměnná = new datovýTyp[počet1][]…[];```
- POZOR!
- Musí se vždy začínat rozměrem nejvíc vně (tj. první závorky zleva)
- Nelze ```proměnná = new datovýTyp[][počet2]…[];```
- Vytvoření pole výčtem hodnot
- I vícerozměrné pole je možné vytvořit výčtem hodnot
- Pole může být pravoúhlé i „zubaté“
- Platí stejná pravidla, jako při vytváření jednorozměrného pole
- Použití samotného výčtu je možné pouze při deklaraci, při pozdějším vytvoření pole je nutné použít i operátor ```new```
#### Přístup k prvkům pole
- Pro přístup k jednotlivým prvkům vícerozměrného pole se používá více indexů
- Počet indexů odpovídá počtu rozměrů pole
- Použití méně indexů než je rozměrů pole
- Při použití méně indexů se nedostaneme k prvku pole, ale k poli s menším rozměrem
- Např. pokud máme dvourozměrné pole a použijeme pouze jeden index, dostaneme se k jednorozměrnému („vnitřnímu“) poli, tj. k „řádce“ pole
- V okamžiku, kdy se dostaneme na „vnitřní“ pole, můžeme zjistit jeho délku
- To se velmi často využívá
- Funguje dobře při procházení vícerozměrného pole, i pokud je pole „zubaté“
### Pole v paměti
- Pole je ve skutečnosti instance speciální třídy a je celé uloženo na haldě (heap)
- Jak to vypadá v paměti při práci s poli, je demonstrováno na příkladu s polem primitivního datového typu a na příkladu s polem objektů
- **Pole nulové délky**
- Pole může mít délku 0 prvků
- Pak nemá žádný prvek, do kterého by šla zapsat hodnota, ale může být použitelná informace o nulové délce
- Rozdíl oproti referenční proměnné pole rovné ```null```
- **Referenční proměnná pole rovná null** neukazuje na žádné pole (**žádné pole není na haldě**)
- Pole nulové délky na haldě existuje a ukazuje na něj referenční proměnná, neobsahuje ale žádný prvek
#### Pole primitivních datových typů v paměti
- Pole primitivních datových typů ve své „instanci“ **přímo obsahuje hodnoty jednotlivých prvků**