1. diel - Úvod do kolekcií a genericita v Jave
V dnešnej lekcii si povieme úvodnú teóriu ku kolekciám v Jave, ktoré si v tomto kurze podrobnejšie rozoberieme.
Kolekcia
Pojem kolekcia označuje súbor dát, ktoré sú väčšinou rovnakého typu
a slúžia na špecifický účel. Počas kurzov sme sa už stretli s dvoma
typmi kolekcií, boli to pole a ArrayList
. Kolekcií existuje
veľké množstvo a hoci navonok často vyzerajú podobne, vo vnútri fungujú
veľmi odlišne a vyberáme si ich podľa konkrétneho účelu. Java disponuje
veľkým množstvom predpripravených kolekcií, s ktorými sa v tejto sekcii
postupne zoznámime a skúsime s nimi pracovať.
Generické a všeobecné kolekcie
Keď sa zamyslíme nad tým, ako by sme si urobili vlastnú kolekciu, určite
by sme po nejakej dobe dospeli k problému. Bol by ním dátový typ kolekcie.
Chceli by sme si napr. naprogramovať vlastný ArrayList
, vytvorili
by sme triedu MyList.java
, do nej pridali príslušné metódy a
všetko potrebné. Pretože však chceme, aby bola naša kolekcia univerzálna a
vedela teda ukladať napr. int
, ako aj používateľa, bude
problém s dátovým typom prvkov vo vnútri kolekcie. Existujú dva varianty,
ako tento problém vyriešiť a aj samotná Java obsahuje kolekcie týchto dvoch
typov.
Všeobecné kolekcie
Keďže vieme, že všetky dátové typy majú ako predka triedu
Object
, môžeme prvky v našej kolekcii ukladať práve do tohto
dátového typu. Do kolekcie teraz môžeme uložiť v podstate čokoľvek.
Nevýhodou je, že sama kolekcia skutočný dátový typ prvkov nepozná a preto
vie prvky navracať len ako všeobecné objekty. Po získaní prvku z kolekcie
si ho teda musíme pretypovať.
Uveďme si príklad kolekcie, pri ktorej neuvedieme generický typ:
ArrayList list = new ArrayList(); list.add("item"); String item = (String)list.get(0);
Po vytvorení listu si do neho pridáme položku typu String
.
Aby sme túto položku mohli z listu získať späť, treba ju na
String
spätne pretypovať.
Pre funkčnosť kódu musíme pridať
import java.util.ArrayList;
.
Generické kolekcie
Generické kolekcie riešia problém s dátovým typom na úrovni jazyka
Java. Zavádza tzv. genericitu. Zjednodušene povedané, ide o možnosť
špecifikovať dátový typ až vo chvíli vytvorenia inštancie. V triede
samotnej kolekcie sa potom pracuje s generickým typom, ktorý slúži ako
zástupca pre budúci dátový typ. Môžeme si to predstaviť tak, že sa
generický typ v triede zmení napr. na String
vo chvíli, keď
vytvoríme jej inštanciu. Ide teda o možnosť triedy nejakým spôsobom
parametrizovať.
Generický ArrayList
už poznáme a onen dátový typ
(parameter) sa generickým triedam špecifikuje v špicatých zátvorkách.
Máme možnosť špecifikovať dátový typ iba raz, pri vytvorení kolekcie.
Akékoľvek ďalšie pretypovanie odpadá:
ArrayList<String> list = new ArrayList<String>(); list.add("item"); String item = list.get(0);
Program funguje úplne rovnako, ako ten s negenerickou kolekciou
ArrayList
, ale čítať môžeme bez nepohodlného
pretypovania.
Generické kolekcie nahradili kolekcie všeobecné a tie sa už príliš nepoužívajú. V kurze sa budeme venovať generickým kolekciám a ich negenerické verzie iba spomenieme.
Genericita
Genericita je samozrejme vlastnosť jazyka Java a my ju máme možnosť vo svojich triedach používať.
Zatiaľ sa nebudeme zaťažovať tvorbou vlastnej kolekcie. Vytvoríme si
triedu, ktorá bude jednoducho spravovať jednu premennú. Premenná bude
generická, teda ľubovoľného dátového typu. Založíme si nový projekt,
konzolovú aplikáciu s názvom genericity
. Pridáme si novú
triedu, pomenujeme ju teraz na študijné účely iba MyClass
. V
jej deklarácii pridáme generický parameter, ktorý pomenujeme
T
:
public class MyClass<T> { }
Generických parametrov môžeme zadať v špicatých zátvorkách viac, oddelíme ich čiarkou. Niekedy sa to môže hodiť, my sa s tým stretneme ďalej pri generických mapách.
Presunieme sa do metódy main()
, kde si vytvoríme inštanciu
našej triedy:
MyClass<Integer> instance = new MyClass<>();
Nezabudneme na špicaté zátvorky tak ako pri dátovom type, tak aj pri
konštruktore. Od Javy 7 nie je potrebné pridávať dátový typ pri
konštruktore. Teraz sme parametru T
v tejto inštancii triedy
určili dátový typ Integer
. Rovnako si môžeme urobiť ďalšiu
inštanciu tej istej triedy a parametru T
dať úplne iný dátový
typ, napr. String
. Stačí nám teda jedna trieda pre viacero
dátových typov.
Pokračujme a vytvorme si v triede atribút. T
môžeme použiť
ako bežný dátový typ:
private T variable;
Triede ešte dodáme konštruktor, ktorý premennú inicializuje:
public MyClass(T variable) { this.variable = variable; }
V main()
aktualizujeme vytvorenie inštancie:
MyClass<Integer> instance = new MyClass<>(10);
Teraz inštancia obsahuje atribút variable
, ktorý je typu
Integer
a nadobúda hodnotu 10
.
Môžeme dokonca pridať metódu, ktorá bude mať navyše ďalší generický parameter (iný, než má trieda). Mohla by vyzerať napr. takto:
public <T2> boolean compare(T2 a) { return variable.equals(a); }
Skúsime si teda porovnať náš Integer
s nejakým iným
typom:
instance.<String>compare("15");
Generický typ si Java dokáže odvodiť z parametra, takže ho nie je potrebné za názvom funkcie uvádzať.
Ďalšia konštrukcia
Pre úplnosť si ešte uveďme niekoľko konštrukcií.
Generický parameter triedy je možné bližšie špecifikovať, presnejšie
obmedziť. Slúži na to kľúčové slovo extends
. Môžeme tak
nastaviť, že daný dátový typ musí napr. implementovať rozhranie
Comparable
:
public class MyClass<T extends Comparable> { ... }
Vďaka tomu môžeme na premenných typu T
teraz vo vnútri
triedy volať metódy z daného rozhrania. Samotné rozhranie môže opäť
obsahovať generický parameter, aby sme generické typy mohli používať aj v
hlavičkách jeho metód.
Nakoniec si ukážme, ako môžeme typ parametra obmedziť z hľadiska dedičnosti.
public class MyClass<A extends B, B extends C, C> { }
Vyššie sme deklarovali triedu s tromi generickými parametrami, kde
A
je potomkom B
a B
je potomkom
C
.
V budúcej lekcii, Java Collections Framework, sa pozrieme, ako na jazyk Java implementovanej kolekcie v rámci Java Collections Frameworku.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 40x (3.25 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java