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

14 KiB
Raw Blame History

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ů