Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Vaše jistota na trhu IT Generické a parametrizované datové typy a metody Rudolf PECINOVSKÝ 1.

Podobné prezentace


Prezentace na téma: "Vaše jistota na trhu IT Generické a parametrizované datové typy a metody Rudolf PECINOVSKÝ 1."— Transkript prezentace:

1 Vaše jistota na trhu IT Generické a parametrizované datové typy a metody Rudolf PECINOVSKÝ 1

2 Vaše jistota na trhu IT Úvod ►Shrnutí či téma 2

3 3 Doporučená literatura 1/2 ►Java 5.0 – Novinky jazyka a upgrade aplikaci ►Vydala Computer Press, ISBN , EAN: ►Probírá vlastnosti, které stále mnozí neznají – především parametrizované typy a anotace ►Lze volně stáhnout na adrese java5novinky/ java5novinky/

4 4 Doporučená literatura2/2 ►CZJUG – Tomáš Záluský ● ►SUN: ● ● ►SUN Generics forum: ● ►Gilad Bracha ● ►Angelika Langer Generic FAQ: ● ►Brian Goetz ● ●

5 5 Terminologie a zkratky ►Používané zkratky: ● GT/ PT– generický/ parametrizovaný typ (typy) ● GM/ PM– generický/ parametrizovaná metoda (metody) ● GTM/ PTM– generické/ parametrizované typy a metody ● TP– typový parametr ►Generický = obecný, obecně použitelný, rodový ● Parametrizovaná metoda != metoda s parametry ►GT/GM mají typové parametry zastupující některé z typů použitých v definovaném typu, resp. metodě ►Seznam typových parametrů se uvádí ve špičatých závorkách ►Parametrizovaný typ je potomek generického typu s dosazenou hodnotou typového parametru ● G: class Typ1G {} interface Typ2G {} ● P : class Typ1P extends Typ1G {} interface Typ2P extends Typ2G {}

6 6 Řešený problém ►Při definici kontejnerů nebylo možno specifikovat typ hodnot ukládaných do kontejneru – typovou kontrolu bylo možno provést až za běhu ►Některé jazyky (např. Ada, C++) řeší tento problém zavedením typových parametrů, jejichž hodnoty je možno kontrolovat již při překladu ►Cíle při implementaci v Javě (2004) ● Maximální kompatibilita s předchozími verzemi Javy ● C++ vyrábí pro každou hodnotu parametru novou třídu – tudy se tvůrci Javy dát nemohli ● Jeden typ musí pracovat stejně dobře pro všechny hodnoty parametru ►Cíle při implementaci v.NET 2.0 (2005) ● Spojit maximum výhod C++ a Javy

7 Cíle generického programování ►Vyjádřit algoritmy s minimální závislostí na použitých datových strukturách ►Vyjádřit datové struktury s minimální závislostí na algoritmech ►Implementovat algoritmy co nejobecněji, aniž by při přechodu ke konkrétním typům došlo ke ztrátě efektivity ►Nevyhovuje-li obecná datová struktura pro speciální případy, poskytnout programátorovi možnost implementovat tyto speciální případy zvlášť ►Existuje-li k řešení určitého problému několik rovnocenných algoritmů, poskytnout programátorovi možnost implementovat je všechny a dát tak uživateli na vybranou podle dalších kritérií 7

8 Řešení v Javě ►Typové parametry generických typů slouží jako informace o typech objektů pouze pro překladač ● Rozhoduje o přípustnosti použitého typu ● V případě potřeby vloží potřebné přetypování ►Přeložený kód je od těchto informací „očištěn“ a žádné dodatečné typové informace již neobsahuje ►Programy je třeba psát tak, aby nebylo třeba za běhu rozhodovat podle hodnot typových parametrů ►Operace vyžadující znalost hodnot typových parametrů za běhu jsou zakázány – způsobí syntaktickou chybu ►Parametrizované typy si pamatují hodnoty typových parametrů svých rodičů 8

9 Řešení v.NET ►Řešení se liší podle specifiky datového typu ● „Hodnotové“ datové typy včetně primitivních mají pro každý použitý typ definovaný speciální verzi (cesta C++) ●Lze to, protože jich je „konečně mnoho“ ● Odkazové datové typy jsou řešeny podobně jako v Javě ►Výhody oproti Javě: ● Generické konstrukce lze používat i pro parametry primitivních typů (Java se omezuje pouze na objektové typy) ● Instance si s sebou nesou informace o hodnotách typových parametrů ►Nevýhody oproti Javě ● Bylo třeba zcela přebudovat virtuální stroj i jazyk IL (.NET byl ale v té době ještě „mládě“, tak to tak moc nevadilo) ● Nedají se použít žolíky ● U „hodnotových“ typů jsou přeložené třídy závislé na třídách, jež je používají, protože potřebují mít vytvořeny příslušné verze 9

10 Vaše jistota na trhu IT Jednoduché použití 10

11 PT + TP – možná použití ►Deklarace atributu či lokální proměnné ● class Třída { T atribut; } ● Map mapa; ● List seznam = new ArrayList<>(); ►Typ parametru či návratové hodnoty ● T max( Collection col ) { /*…*/ } ►Typ vyhozené výjimky ● public void metoda() throws E { /*…*/ } ►Potomek generického předka ● class ChytrýSeznam extends ArrayList { /*…*/ } 11

12 Poznámky ►Seznam typových parametrů je součástí názvu třídy ►Parametr je možné použít všude, kde bychom použili příslušnou třídu ►Analogie s metodami: formální a skutečné parametry ►Typ prvků ve frontě bude určen až při vytváření konkrétní instance fronty ►Různé instance mohu ukládat objekty různých typů ►Hodnoty typových parametrů jsou známy pouze v době překladu => typové parametry nelze použít v situacích, kdy je třeba znát jejich hodnoty za běhu 12

13 VŠE – 05 Copyright © 2006, Rudolf Pecinovský 13 Definice vlastního generického typu public class FrontaP { List prvky = new ArrayList (); public FrontaP() {} public void zařaď( E prvek ) { prvky.add( prvek ); } public boolean isPrázdná() { return (prvky.size() == 0); } public E další() { E ret = prvky.get(0); prvky.remove(0); return ret; } public String toString() { return prvky.toString(); } ►Třída FrontaP pracuje s objekty typu E ● FrontaP = Fronta s typovým Parametrem ►Pomocí typového parametru definujeme skutečný typ objektů ve frontě ● FrontaP ►Hodnota TP specifikuje typ parametru či typ návratové hodnoty

14 Dědičnost parametrizovaných typů1/2 14 public class FrontaPI extends FrontaP implements Iterable { public Iterator iterator() { return new Iterator () { int pořadí = 0; public boolean hasNext() { return (pořadí < prvky.size()); } public E next() { return prvky.get( pořadí++ ); } public void remove() { prvky.remove( 0 ); } }; } ► FrontaP = fronta s (typovým) parametrem FrontaP ► FrontaPI = FrontaP iterovatelná

15 Dědičnost parametrizovaných typů2/2 ►Můžeme definovat potomka, který bude i nadále generický (příklad na minulé stránce), anebo parametrizovaného potomka (příklad na této stránce), tj. potomka s konkrétní hodnotou typového parametru – parametrizovaného typu ►V uvedené třídě není třeba definovat nic nového – hodnota typového parametru je pouze informaci pro překladač ► FrontaPIS = FrontaPI „stringů“ 15 public class FrontaPIS extends FrontaPI { //Nepotřebuje další upřesnění, vše říká TP (typový parametr) }

16 Metody s typovými parametry ►Jako generické můžeme definovat nejenom datové typy, ale i jednotlivé metody ►Typové parametry se uvádějí před typem návratové hodnoty ►Při volání takovéto metody si skutečnou hodnotu TP překladač často domyslí; pokud ne, musíme ji uvést ►Skutečnou hodnotu TP píšeme za kvalifikaci => potřebujeme-li uvést TP, musíme metodu kvalifikovat, i když by to jinak nebylo potřeba 16

17 Příklad generické metody public class Metody { public static List dvojice( T prvek ) { List ret = new ArrayList (); ret.add( prvek ); return ret; } public void volání() { Metody m = new Metody(); List ls = dvojice( "Text" ); List lo; // lo = dvojice( "Text" ); //Nesouhlasí typy // lo = dvojice("objekt"); //Nekvalifikované lo = Metody. dvojice("Kvalifikace třídou"); lo = m. dvojice( "Kvalifikace instancí"); lo = dvojice( (Object)"Řešení přetypováním" ); } 17

18 Vaše jistota na trhu IT Omezení hodnot typových parametrů 18

19 VŠE – 05 Copyright © 2006, Rudolf Pecinovský 19 Motivace ►Občas potřebujeme, aby typové parametry vyhovovaly daným omezením – např. aby implementovaly nějaké rozhraní public class IntervalU > { private final T dolní, horní; public IntervalU( T dolní, T horní ) { if( dolní.compareTo( horní ) > 0 ) throw new IllegalArgumentException( "Dolní mez nemůže být větší než horní" ); this.dolní = dolní; this.horní = horní; } public T getDolní() { return dolní; } public T getHorní() { return horní; } public boolean uvnitř( T t ) { return (dolní.compareTo( t ) <= 0) && (t.compareTo( horní ) <= 0); } I pro implementaci rozhraní se používá extends

20 Syntaxe1/2 ►TP je potomkem definovaného typu nebo implementuje definované rozhraní (horní omezení) T extends Rodič ►Klíčové slovo extends se uvádí jak pro dědičnost (rodič je třída), tak pro implementaci (rodič je interface ) ►Musí-li být TP „potomkem“ několika jiných typů oddělujeme tyto typy znakem &: T extends Typ1 & Typ2 & Typ3 ● Čárka je nepoužitelná, protože odděluje jednotlivé parametry, např. Generický ►Má-li být potomkem třídy a současně implementovat nějaké rozhraní, musí být jeho rodičovská třída uvedena jako první: T extends Rodič & Rozhraní1 & Rozhraní2 20

21 Syntaxe2/2 ►Dříve uvedený parametr se v definici může vyskytnout znovu: TestSeznamů > Posluchač > ►Nejsou povoleny dopředné reference TestSeznamů, E> ►Můžeme také požadovat, aby typový parametr byl předkem definovaného typu (dolní omezení): T super Potomek ►Dolní omezení lze klást pouze na žolíky (viz dále) ►Není možno současně požadovat extends i super 21

22 Vaše jistota na trhu IT Očišťování a jeho problémy 22

23 Terminologie ►Ozdobený datový typ (decorated type) – typ doplněný o typové parametry (skutečné hodnoty) ►Očištěný (surový, neozdobený) typ (row type) – typ použitý v přeloženém programu, zbavený případných informací nesených typovými parametry ►Při překladu se datové typy očišťují (erasure), takže v přeloženém programu není možno informace o hodnotách typových parametrů použít ►Při očišťování překladač vloží potřebná přetypování 23

24 Princip očištění ►Je-li na TP kladeno nějaké horní omezení, bude za něj v přeloženém kódu substituován požadovaný rodič ►Není-li na TP kladeno žádné horní omezení, bude za něj substituován typ Object ►Má-li TP několik horních omezení, bude pro substituci použito první z nich ►Neuvědomíme-li si všechny důsledky očistění, můžeme do programu zanést nechtěné chyby 24

25 Vliv pořadí uvedeny TP na kód 25 class Čištění_Před & Serializable, SC extends Serializable & Comparable > { CS cs; SC sc; void upravCS( CS p ) { if(cs.compareTo(p) < 0) cs = p; } void upravSC( SC p ) { if(sc.compareTo(p) < 0) sc = p; } } public class Čištění_Po { Comparable cs; Serializable sc; void upravCS(Comparable p) { if(cs.compareTo((Object)p) < 0) cs = p; } void upravSC(Serializable p) { if(((Comparable)sc).compareTo((Object)p) < 0) sc = p; }

26 Nejednoznačnosti a kolize ►Falešně přetížená metoda ● Metoda, která má po očištění stejnou signaturu, jako metoda již existující ►Nová metoda koliduje se zděděnou ● Metoda, která se tváří, že nepřekrývá zděděnou metodu, ji po očištění začne překrývat ►Kolize požadovaných rozhraní ● Dceřiná třída dědí rozhraní implementované svým rodičem včetně hodnoty případného typového parametru, kterou je často typ rodiče, ale potomek by potřeboval sebe ►Špatné pochopení dědičnosti typů ● Rozebráno v dalších kapitolách 26

27 Příklad: Falešně přetížená metoda public class Přepravka12 { T1 první; T2 druhý; public T1 get1() { return první; } public T2 get2() { return druhý ; } public void set( T1 o ) { první = o; } public void set( T2 o ) { druhý = o; } } 27 ►Obě metody set mají ve skutečnosti stejné typy parametrů

28 Příklad: Nová metoda koliduje se zděděnou public class Přepravka11 { T první; T druhý; public T get1() { return první; } public T get2() { return první; } public boolean equals( T t ) { return (první.equals(t) && druhý.equals(t)); } 28 ►Metoda equals je po očištění definována jako equals(Object), ale přitom neakceptuje libovolný objekt, a proto nepřekrývá korektně zděděnou verzi

29 Příklad: Kolize požadovaných rozhraní class Rodič implements Comparable { public int compareTo(Rodič r) { return 0; } } //=============================================================== class Potomek extends Rodič {} //=============================================================== class Kolize_NesedíRozhraní { //Toto ještě projde – potomek se vydává za rodiče IntervalU iur = new IntervalU ( new Rodič(), new Potomek() ); //Implementuje špatné rozhraní – //zdědil implementaci Comparable, //avšak konstruktor požaduje implementaci Comparable IntervalU iup = new IntervalU (new Potomek(), new Potomek()); } 29 IntervalU >

30 Příklad: Kolize implementovaných rozhraní class Rodič implements Comparable { public int compareTo( Rodič r ) { return 0; } } //================================================================== class Potomek extends Rodič implements Comparable {} 30 ►Kód vyvolá při překladu chybu java.lang.Comparable cannot be inherited with different arguments ►Příčina: nelze implementovat stejné rozhraní jako rodič, ale s odlišnými hodnotami typových parametrů

31 Příklad: Špatné pochopení dědičnosti ►Program: /*1*/ List str = new ArrayList (); /*2*/ List obj = str; //Chyba!!! /*3*/ obj.add(new Object()); /*4*/ String s = str.get(0); špatně interpretuje dědičnost generických typů ►Dědičnost typových parametrů neimplikuje dědičnost typů s těmito parametry ● Je to jinak než u polí – tam je pole potomků potomkem pole předků 31

32 Dědičnost parametrizovaných typů 32 List «surový» ArrayList «surový» List ArrayList List

33 Vaše jistota na trhu IT Nepovolená použití 33

34 34 new TP ►Nelze vytvořit instanci typového parametru pomocí operátoru new ● atribut = new T(); ● K vytvoření instance potřebuji konstruktor. ● Nevím, jaké konstruktory bude daný typ poskytovat ● Instance lze vytvářet jen klonováním či továrními metodami ►Lze ale vytvořit instancí parametrizovaného typu ● List seznam = new ArraList () ● Konstruktor parametrizovaného typu je známý, takže překladač přesně ví, kterou metodu zavolat

35 35 new PT[]; primitivní TP ►Nelze vytvořit pole instancí typového parametru ani parametrizovaného typu ● pole1 = new T[](); pole2 = new ArraList (); ● Pole si musí umět pamatovat deklarovaný typ svých prvků Object[] oo = new String[5]; oo[0] = 123; //Vyvolá běhovou chybu ● Neznám-li skutečný typ prvků, nemohu pole vytvořit ►Hodnotami typových parametrů nesmí být primitivní typy ● List seznamCelýchČísel; ● Koncepce PT je v Javě založena na dědičnosti – do ní primitivní datové typy nezapadají

36 36 Statické členy; Throwable ►Typové parametry třídy není možno použít u jejích statických členů ● classs Třída { static T atribut; static T metoda( T param ); } ● Statické členy jsou sdíleny instancemi dané třídy ● Každá z instancí může mít přiřazenu jinou hodnotu typového parametru => neví se, kterou z nich aplikovat ● V případě potřeby musejí mít statické metody vlastní typový parametr ►GT nesmí být potomkem Throwable ● class Výjimka extends Exception {/*…*/} ● Při vyhazování výjimky nevíme, kdo ji zachytí, a nemůžeme mu proto předat informace, od nichž byla instance očištěna => parametrizace výjimky nemá smysl

37 37 Výčtový PT; instanceof ; TP.class ►Výčtové typy ● enum Výčet {/*…*/} ● Výčtové typy mají své instance definovány přímo ve třídě kde se všechny potřebně typy nastaví rovnou => není tu místo pro budoucí volbu ● Navíc jsou příliš těsně provázané se svým rodičem, překladačem a virtuální strojem ►Nelze použít operátor instanceof ● if (variable instanceof List ) //… ►Nelze použít literál class-objektu ● Class clt = T.class; Class > cls = List.class; ● Literál je konstanta, jejíž hodnota je známa v době překladu. To ale u TP známo není ● PT zase nepřidá využitelnou informaci

38 38 TP jako rodič; import PT ►TP nelze použít jako rodiče ● class Foo extends T; ● Konstruktor musí volat konstruktor předka, ale toho nezná ►Nelze použít ● import java.util.List ; ● V příkazu import lze používat pouze surové, neozdobené typy

39 Vaše jistota na trhu IT Žolíky 39

40 40 Účel ►Slouží k řešení problémů způsobených omezeními dědičnosti parametrizovaných typů ►Může-li na daném místě být objekt libovolného typu, použijeme žolík ? ● Class třída = parametr.getClass(); ►Může-li být na daném místě objekt libovolného typu vyhovujícího zadanému omezení, použijeme žolík s příslušným omezením ● Pro potomka typu X: ● Pro rodiče typu Y: ● Omezení lze kombinovat: >

41 Příklad: Žolík jako potomek public static void test() { List lik; lik = new ArrayList (); naplň( lik ); nakresli( lik ); lik = new LinkedList (); naplň( lik ); nakresli( lik ); } public interface IMístnost extends IPojmenovaný public String getNázev(); public String getPopis(); public Collection getPředměty(); public Collection getSousedé(); } 41

42 Příklad: Žolík jako předek // public class IntervalUž > public class SrovnáníRozhraníŽolíkem { class Rodič implements Comparable public int compareTo( Rodič r ) { return 0; } } class Potomek extends Rodič {} // implements Comparable {} IntervalUž iur = new IntervalUž ( new Rodič(), new Potomek() ); IntervalUž iup = new IntervalUž ( new Potomek(), new Potomek() ); } 42

43 Vaše jistota na trhu IT Děkuji za pozornost ►Rudolf Pecinovský mail: ICQ:

44 44

45 Pgm Používaná písma a objekty ► Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Demi) ● Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Medium) ● Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Cond) ►Příliš žluťoučký kůň úpěl ďábelské ódy (Heavy) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Franklin Gothic Book) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Comic Sans MS) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Consolas) Program Keyword Opakování Příliš žluťoučký kůň úpěl ďábelské ódy 45


Stáhnout ppt "Vaše jistota na trhu IT Generické a parametrizované datové typy a metody Rudolf PECINOVSKÝ 1."

Podobné prezentace


Reklamy Google