+ All Categories
Home > Documents > CZJUG – 21. února 2007

CZJUG – 21. února 2007

Date post: 19-Jan-2016
Category:
Upload: pepper
View: 41 times
Download: 0 times
Share this document with a friend
Description:
CZJUG – 21. února 2007. Generické typy v Javě Ing. Tomáš Záluský http:// www.zalusky.eu ET NETERA, a.s. http://www.etnetera.cz. Agenda. Úvod Generické typy (třídy, terminologie) Generické typy (metody, wildcards) Aplikace v Javě Praktické situace při používání generik Diskuse/dotazy. - PowerPoint PPT Presentation
73
1/73 CZJUG – 21. února 2007 Generické typy v Javě Ing. Tomáš Záluský http://www.zalusky.eu ET NETERA, a.s. http://www.etnetera.cz
Transcript
Page 1: CZJUG –  21. února 2007

1/73

CZJUG – 21. února 2007

Generické typyv Javě

Ing. Tomáš Záluskýhttp://www.zalusky.eu

ET NETERA, a.s.http://www.etnetera.cz

Page 2: CZJUG –  21. února 2007

2/73

Agenda

● Úvod● Generické typy (třídy, terminologie)● Generické typy (metody, wildcards)● Aplikace v Javě● Praktické situace při používání generik● Diskuse/dotazy

Page 3: CZJUG –  21. února 2007

3/73

Když se řekne generický typ● „přestaňte mi nadávat, nerozumím vám“

– kdo nikdy o g. neslyšel v žádném jazyce● „jo, to jsou ty zobáky, abys nemusel furt

přetypovávat ty prvky Listu“– základní kolekce, začátky

● „to, co je v Javě, je dobrý, ale na svý věci to moc nevyužívám, a ty otazníky fuj to je magie“– aktivní používání cizího kódu, občas vlastní

● „už jsem si někdy udělal třídy, kde jsem využil meze, wildcards nebo triky s inferencí a je to užitečný, i když mě to občas vypeklo“– návrh několika vlastních (spolupracujících) g. tříd

Page 4: CZJUG –  21. února 2007

4/73

Úvod

● o přednášce● dotazník, různé názory na generiky● očekávání z přednášky

– teorie/praxe, úroveň pokročilosti– přednáška pro kodéry, ne pro architekty– snaha o výklad formou „uzavřený systém“, i za

cenu nepřesností a zjednodušení● co od přednášky neočekávat

– spekulace nad budoucím vývojem– Bolí vás zuby? Generické třídy Vám pomůžou!

Page 5: CZJUG –  21. února 2007

5/73

Motivace

● podobnost algoritmů a datových struktur● příklad: seznam řetězců x seznam čísel class SeznamRetezcu { private String array[]; ... public String get(int index) {return array[index];} public void set(int index, String value) {array[index] = value;} public String toString() ... public String max(Comparator comp) { String temp = array[0]; for (String current : array) { if (comp.compareTo(current,temp) > 0) {temp = current;} } return temp; }}class SeznamCisel { private Integer array[]; ... public Integer get(int index) {return array[index];} public void set(int index, Integer value) {array[index] = value;} public String toString() ... ...}

Page 6: CZJUG –  21. února 2007

6/73

Motivace – nevýhody ukázky…

● vnější (mezi různými třídami)– opakující se copy & paste kód– není (jazykově) vyjádřena souvislost mezi třídami

● jak by vypadal předek AbstractSeznam? moc by nepomohl

– obtížné rozlišení typu za běhu● reflection, Class.forName("Seznam" + chciInt? "Cisel" : "Retezcu")

Page 7: CZJUG –  21. února 2007

7/73

…Motivace – nevýhody ukázky

● vnitřní (v rámci jedné třídy)– není vyjádřena souvislost mezi členy třídy

● např. shoda typu vkládané a vybírané hodnoty– není vyjádřena souvislost mezi parametry metody

navzájem, nebo mezi parametry a návratovou hodnotou

● např. u max() by mělo být zaručeno, že Comparator porovnává objekty stejného typu, jaké vrací max()

● kód je pouze demonstrativní– znalost nevýhod může být důležitá z hlediska

rozhodování se, zda pro řešení daného problému použít generiky

Page 8: CZJUG –  21. února 2007

8/73

Možnosti nápravy…

● náhrada za co nejuniverzálnější typ– tj. Object– Java do příchodu 5.0

● odstraní pouze část nevýhod– opakující se kód– vyjádření souvislosti mezi třídami – zadarmo

(založením předka)– rozlišení typu zůstává za běhu za pomoci instanceof

– nevýhody na lokální úrovni zůstávají– zvýšená potřeba přetypovávání

Page 9: CZJUG –  21. února 2007

9/73

…Možnosti nápravy…

● generický/parametrizovaný Seznam: (parametrizovaný typem)

class Seznam<T> { private T array[]; ... public T get(int index) {return array[index];} public void set(int index, T value) {array[index] = value;} public String toString() ... public T max(Comparator<T> comp) { // spravne <? super T>, ale tady T temp = array[0]; // to staci for (T current : array) { if (comp.compareTo(current,temp) > 0) { temp = current; } } return temp; }}Seznam<String> seznamRetezcu = new Seznam<String>();

Page 10: CZJUG –  21. února 2007

10/73

…Možnosti nápravy

● odstranění všech výše uvedených nevýhod– opakující se kód– zachování souvislostí mezi třídami– rozlišení typu přechází do compile-time– zachování typových souvislostí mezi členy třídy i v

rámci kontraktu metod

Page 11: CZJUG –  21. února 2007

11/73

Historie a souvislosti

● C++ template● JSR-14 (http://jcp.org/en/jsr/detail?id=14)● Java 5.0 „Tiger“

Page 12: CZJUG –  21. února 2007

12/73

Generické typy I.

● OOP● Generické třídy● Raw typ, erasure, meze● Vztah mezi parametrickými typy

Page 13: CZJUG –  21. února 2007

13/73

Jemné připomenutí OOP…

● rozdíl– statický (=deklarovaný) x dynamický (=runtime) typ– List list = new ArrayList();

● „potomek“ a „předek“– kompatibilita vzhledem k přiřazení – dědičnost x implementace interfacu – není tak důležité– objektová hierarchie– kořen Object, větvení stromu „oběma směry“

class Parent {...}class Child extends Parent {...}Parent parent = new Parent(); // lzeChild child = new Child(); // lzeParent parent = child; // lze, ale nutny cast((Child)parent).childMethod();Child child = parent; // nelze, za parentem muze byt v runtime // jiny potomek

Page 14: CZJUG –  21. února 2007

14/73

…Jemné připomenutí OOP

Page 15: CZJUG –  21. února 2007

15/73

Úvod do generických typů

● T = typový parametr● typový argument

– konkrétní typ dosazený za typový parametr

● parametrizovaný typ– generický typ po dosazení typového argumentu za typový

parametr

● analogie s voláním metod– deklarace: void foo(int p) {...} // p je parametr– volání: foo(2); // 2 je argument

● různé terminologie– parametrizovaný typ x instance parametrizovaného typu– pozor: neplést s instancí ve smyslu nového objektu vytvořeného

pomocí new!

Page 16: CZJUG –  21. února 2007

16/73

Odlišnost koncepcí v C++ a Javě

● C++ přístup– každá instance se přeloží do zvláštní třídy, jakoby se

dosadil argument na úrovni zdrojového souboru (makro)

– vytvoří se tolik „syntetických“ tříd, kolik je instancí generického typu

– typová informace je přístupná za běhu● Java přístup

– při překladu se provede kontrola vztahů mezi objekty z hlediska typové kompatibility (přiřazení, cast)

– poté se typová informace odstraní (není tedy přístupná za běhu) a zůstane jedna třída

– tím je zaručena runtime typová bezpečnost

Page 17: CZJUG –  21. února 2007

17/73

Generické třídy

● zápisclass Nazev <TypovyParametr1,...> {

// telo tridy

}

● code convention– doporučení: 1písmenný typový parametr– klíč mapy K, hodnota mapy/kolekce V (T,E), výjimka E

(X), obecný typ T (U,…)● typové parametry v <>

– jsou součástí názvu generické třídy– mohou se používat zhruba kdekoli, kde se očekává

třída, tj. přesně:

Page 18: CZJUG –  21. února 2007

18/73

Použití generických tříd – kde ano

● tvorba nové instance:... = new ArrayList<T>()

● použití na levé straně přiřazení:List<T> list = ...– přiřazení pole je sice možné, ale nepřináší výhody:

List<T>[] arrayOfLists = ...● deklarace lokální a instanční proměnné:

private List<T> list = ...● vyhození výjimky generického typu:

public <E extends Exception> void method()throws E {...}

● potomek generického předka:public class MySmartList<T> implements List<T>...

Page 19: CZJUG –  21. února 2007

19/73

Použití generických tříd – kde ne…

● generické výjimky– generický typ nesmí být odvozen od Throwable

class MyException<T> extends Exception ...● generický enum:

enum Foo<T> {...}● přímá tvorba objektu nebo pole operátorem new:

new T(); new T[] {...}● instanceof:

if (variable instanceof List<String>) ...● class literal:

Class<List<String>> clazz = List<String>.class; ● přímo jako supertyp:

class Foo<T> extends T;

Page 20: CZJUG –  21. února 2007

20/73

…Použití generických tříd – kde ne

● tvorba pole prvků generického typu

new ArrayList<T>[]

● import

import java.util.List<String>;

● statický kontext– proměnné, metody, vnitřní statické třídy, interfacy, enums:

01 public class Foo <T,U> {02 static class FooStaticClass {03 void hoo(T arg) {}04 }05 class FooClass {06 void hoo(T arg) {} P U Z Z L E:07 }08 interface FooInterface { Na kterých řádcích ohlásí09 void hoo(T arg); překladač chybu?10 }11 interface Hoo<T> {12 void hoo(T arg,13 U arg2);14 } }

Page 21: CZJUG –  21. února 2007

21/73

…Použití generických tříd – kde ne

● tvorba pole prvků generického typu

new ArrayList<T>[]

● import

import java.util.List<String>;

● statický kontext– proměnné, metody, vnitřní statické třídy, interfacy, enums:

01 public class Foo <T,U> {02 static class FooStaticClass {03 void hoo(T arg) {} // NELZE - static context04 }05 class FooClass {06 void hoo(T arg) {} // OK07 }08 interface FooInterface {09 void hoo(T arg); // NELZE - static context10 }11 interface Hoo<T> {12 void hoo(T arg, // T je zcela nový typ, OK13 U arg2); // U je zakázaný14 } }

Page 22: CZJUG –  21. února 2007

22/73

Generické třídy

● typový parametr – pouze referenční typ, tj.:● ano:

– přímo typ, tj. vše, co extends Object:

new ArrayList<String>()– pole:

new ArrayList<String[]>()– generický typ:

new ArrayList<ThreadLocal<String>>()– wildcard typ:

new ArrayList<ThreadLocal<?>>()● ne:

– primitivní typ a void– wildcard:

new ArrayList<?>()

Page 23: CZJUG –  21. února 2007

23/73

Generické třídy

● parametrizovaný typ:

List<String> listOfStrings = new ArrayList<String>();

● typová kontrola:– překladač ohlídá správný typ:

listOfStrings.add(2005); // chyba– snížení castů:

String s = listOfStrings.get(1);

Page 24: CZJUG –  21. února 2007

24/73

Terminologie

● raw type– raw = základní, surový, čistý– typ po odstranění typových parametrů– raw typ ke generickému typu List<String> je List

● type erasure– erasure = vymazání, očištění– proces odstranění typového parametru z generického

typu– provádí jej překladač po kontrole typové kompatibility

Page 25: CZJUG –  21. února 2007

25/73

Důsledky

● za běhu se pracuje pouze s raw typem– Příklad: listOfStrings.getClass().getName()– vrací "java.util.List"– nikoli "java.util.List<String>"

● snaha vyhnout se raw typům v deklaracích– může komplikovat závislost na kódu třetí strany

● type erasure = společný důvod všech „kde ne“– např. statický kontext – společný všem instancím

generické třídy– new T – překladač by nevěděl, co má nechat vytvořit,

protože vidí jen Object● typová informace se nedostane do .class souboru

Page 26: CZJUG –  21. února 2007

26/73

Shrnutí

● generiky (téměř) nejsou záležitostí runtime !!!

Page 27: CZJUG –  21. února 2007

27/73

Meze generických parametrů (bounds)

● specifikují úžeji třídu nebo rozsah tříd typových argumentů● zápis:

– T extends HorniMez T může být HorniMez nebo její potomek (přetížení klíčového slova extends)

– T extends HorniMez & Interface1 & Interface2 T musí splňovat výše uvedenou podmínku pro všechny typy oddělené znakem &

● zúžení typu parametrů může být– absolutní: class Trida <T extends Number> {...}– vzájemné: class Trida <S, T extends S> {...}

● není-li mez uvedena, chápe se jako Object.● type erasure je náhrada typu mezí

Page 28: CZJUG –  21. února 2007

28/73

Vztah mezi instancemi generického typu

● List<Integer>– může obsahovat pouze instance třídy Integer

● List<Number>– může obsahovat Integer, Long, Short,...– homogenita a heterogenita jsou relativní pojmy– homogenní = nemohou v něm být Stringy– heterogenní = mohou v něm být různí potomci Number

● mezi instancemi generického typu neexistuje dědění ani kompatibilita vzhledem k přiřazení

● a to ani tehdy, pokud to platí pro typové argumenty

Page 29: CZJUG –  21. února 2007

29/73

Instance generického typu – příklad

● důvod:– pokud by to bylo přípustné, šlo by do objektu listOfNumbers uložit Long přes proměnnou listOfNumbers a pak ji chtít vybrat přes listOfInteger => ClassCastException

● rozdíl:statický (deklarovaný) x dynamický (runtime) typ– stejné jako před generikami

List<Integer> listOfIntegers;List<Number> listOfNumbers;listOfIntegers = new ArrayList<Number>(); // chybalistOfNumbers = new ArrayList<Integer>(); // chybalistOfIntegers = listOfNumbers; // chybalistOfNumbers = listOfIntegers; // chybalistOfIntegers = (List<Integer>)listOfNumbers; // chybalistOfNumbers = (List<Number>)listOfIntegers; // chyba

Page 30: CZJUG –  21. února 2007

30/73

Vztah generického typu a raw typu

● přiřazení i cast jsou možné, ale vedou na – ● unchecked warning

– upozornění překladače, že nemá dost informací, aby zajistil typovou bezpečnost

– uživatel se dívá na objekt pohledem, který mu umožňuje s ním neoprávněně pracovat

– typicky: vložit do kolekce „vetřelce“– v Eclipse hláška „Type safety“ – při přechodu z 1.4 nevyhnutelné– z dlouhodobého hlediska nežádoucí

a měly by se eliminovat

Page 31: CZJUG –  21. února 2007

31/73

Potlačení unchecked warningu

● anotace @SuppressWarnings("unchecked") ● použití

– pokud překladač hlásí unchecked warning, ale ze situace plyne, že práce s typy je bezpečná

– v případě specifické kombinace lenosti, nechutě opravovat warningy a časové tísně

● anotovat lze třída nebo metoda● potlačí všechny warningy v metodě ()

Page 32: CZJUG –  21. února 2007

32/73

Odůvodněný @SuppressWarnings

● 2 ukázky: klonování + obejití statického kontextu

public static class Wrapper<T> implements Cloneable {@SuppressWarnings("unchecked")public Wrapper<T> safeClone() throws CloneNotSupportedException {

return (Wrapper<T>)this.clone();}

}

public static class EmptyIterator <T> implements Iterator<T> {

private static EmptyIterator instance = new EmptyIterator();

private EmptyIterator() {}

@SuppressWarnings("unchecked")public static <U> EmptyIterator<U> getInstance() {

return (EmptyIterator<U>)instance;}

public boolean hasNext() {return false;

}...

}

Page 33: CZJUG –  21. února 2007

33/73

Generické typy II.

● Generické metody● Wildcards

Page 34: CZJUG –  21. února 2007

34/73

Generické metody

● metody mohou být parametrizované podobně jako třídy

● zápis:– deklarace typových parametrů se zapisuje před

návratovou hodnotu– příklady:public <T> int foo(T object) {...}public <T> T max(Collection<T>) {...}

● parametrizovaná metoda(instance generické metody)– analogie k parametrizované třídě– tj. metoda po dosazení typových argumentů za typové

parametry

Page 35: CZJUG –  21. února 2007

35/73

Genericita třídy a metody

● jsou nezávislé rysy● generická třída i generická metoda

– příklad:java.util.Collection<E>public <T> T[] toArray(T[])

– parametry spolu nesouvisejí, případně se zastiňují● negenerická třída, generická metoda

– příklad:java.util.Collectionsstatic <T> List<T> singletonList(T o)většina metod

● ostatní kombinace

Page 36: CZJUG –  21. února 2007

36/73

Inference…

● type argument inference = odvození typového argumentu– proces nalezení instance generické metody– na základě typu jednotlivých částí kontraktu metody – odehrává se za překladu

public class GenericMethod { public static <T extends Number> void gm(T par) { System.out.println("Number"); } public static <T extends Integer> void gm(T par) { System.out.println("Integer"); } public static <T extends String> void gm(T par) { System.out.println("String"); } public static void main(String[] args) { GenericMethod.gm(1); // Integer GenericMethod.gm("abc"); // String GenericMethod.<Number>gm(1); // Number Number number = new Integer(1); GenericMethod.gm(number); // Number} }

Page 37: CZJUG –  21. února 2007

37/73

…Inference…

● mechanismus inference– opírá se jak o typ předaných parametrů, tak o typ

návratové hodnoty– může se lišit v Eclipse compileru a javacu– může vypéct

Page 38: CZJUG –  21. února 2007

38/73

…Inference

● explicitní specifikace typu argumentu– sdělíme sami překladači, jaké argumenty dosadit

● u generických tříd vždy– návrhy do JDK7 na zjednodušeníList<String> list = new ArrayList();

● u generických metod potřeba, když automatický mechanismus neodpovídá záměrům programátora

● důvody použití:– negativní: lenost, nechce se zabývat inferencí– pozitivní: snaha o defenzivnost

(zajištění přeložitelnosti na více překladačích)● u instančních metod nutno použít this

this.<Number>gm(1);

Page 39: CZJUG –  21. února 2007

39/73

Wildcards…

● co je wildcard– označení pro určitou přesně vymezenou množinu

parametrizovaných typů– prostředek pro zastřešení nekompatibilních

parametrických typů do hierarchie● příklady

– List<? extends Number>– Comparable<? super Integer>– Collection<?>– Map<String,? extends List<T>>

Page 40: CZJUG –  21. února 2007

40/73

…Wildcards…

● zápis– ? – neomezený wildcard

● unbounded● čteme: „cokoli“ nebo „neznámý typ“

– ? extends HorniMez – shora omezený● upper bound● čteme: „cokoli co je HorniMez nebo potomek“

– ? super DolniMez – zdola omezený● lower bound● čteme: „cokoli co je DolniMez nebo předek“

● meze mají syntaxi odlišnou od mezí g. typů– žádné vícenásobné meze (&), ale zase super

● další přetížení klíčového slova extends

Page 41: CZJUG –  21. února 2007

41/73

…Wildcards…

● wildcard typy– nejsou konkrétní generické typy jako List<String>, Comparable<Number>,…

– ale je nutno je za nimi vidět– wildcard typ se také nazývá rodina konkrétních instancí

generického typu● zápis List<? extends Exception> …

– ...je potřeba číst jako: „homogenní seznam objektů Exception nebo objektů třídy, která je potomkem Exception“

– ...nelze číst jako „seznam, ve kterém může být cokoli, co je potomkem Exception“

– nesprávnému chápání by odpovídal typ List<Exception>, který je pouze podmnožinou wildcard typu

● homogenita x heterogenita– rozdíl Collection<?> x Collection<Object> – viz diagram

Page 42: CZJUG –  21. února 2007

42/73

…Wildcards…

Page 43: CZJUG –  21. února 2007

43/73

…Wildcards…

● mezi wildcard typy existuje vztah velmi podobný dědění– můžeme používat pojmy „předek“ a „potomek“– wildcard typ T1 je předkem wildcard typu T2, jestliže odpovídající

množina konkrétních parametrizovaných typů pro T1 je nadmnožinou množiny konkrétních parametrizovaných typů pro T2

– lidsky řečeno: když jsou bubliny na obrázku v sobě– kompatibilita vzhledem k přiřazení

● jak zjistit, zda 2 typy jsou ve vztahu předek-potomekpublic class Inheritance {

public static <T,U extends T> void test() {}public static void main(String[] args) {

Inheritance.<Object,String>test();Inheritance.<Collection<? extends Number>,

Collection<? extends Integer>>test();}

}

Page 44: CZJUG –  21. února 2007

44/73

…Wildcards

● wildcards je užitečné znát, protože– poskytují vazbu mezi jednotlivými instancemi

generického typu– současně tvoří hierarchii, analogie s hierarchií objektů

● root je Object x Rawtype<?>● wildcard typy x abstraktní třídy

– hierarchie není strom, ale acyklický graf

Page 45: CZJUG –  21. února 2007

45/73

Wildcards – pokročilejší

● capture („otisk“, ne „záchytka“ )– fiktivní konkrétní typ, který představuje wildcard typ– je to syntetický typ, se kterým operuje interně překladač při

kontrole zajištění typové bezpečnosti– objevuje se v chybových hlášeních

● omezení volání metod na objektu wildcard typu– List<?> list = ...list.add(1); // chyba

– důvod: neznalost konkrétního parametrizovaného typu– zakázanost metody je dána výskytem T v argumentech metody– metoda vracející T je povolena, přístup přes Object– u omezených wildcards složitější

● víceúrovňové wildcard

Page 46: CZJUG –  21. února 2007

46/73

Aplikacev Javě

● Collections● Class● Ostatní

Page 47: CZJUG –  21. února 2007

47/73

Collections…

● java.util.Iterable<E> a potomci● java.util.Collection<E>

– void addAll(Collection<? extends E>)● aby bylo možné přidat i kolekci potomků, taktéž u Map.putAll()

– Iterator<E> iterator()– <T> T[] toArray(T[]) // <T super E>

● převede na pole, jehož runtime typ je určen runtime typem zadaného pole● java.util.Iterator<E>● java.util.Map<K,V>

– java.util.Map.Entry<K,V>– Set<Map.Entry<K,V>> entrySet()– Set<K> keySet()– void putAll(Map<? extends K,? extends V>)– Collection<V> values()

Page 48: CZJUG –  21. února 2007

48/73

…Collections…

● java.util.Collections<E> (statické metody)– <T> boolean addAll(Collection<? super T>, T...)

● umožní zadat potomka do kolekce předků, nelze totiž<T> boolean addAll(Collection<T>, ? extends T...)

– <T> int binarySearch(List<? extends Comparable<? super T>>, T)

● umožní vyhledat potomka v seznamu předků v případě, že Comparable je definováno na předkovi

– <E> Collection<E> checkedCollection(Collection<E>, Class<E>)

● kolekce s kontrolou typové bezpečnosti za běhu● brání zavlečení nepořádku v podobě směsi generických a raw typů● myšlenka:

když už se nepodaří přesunout kontrolu z runtime do compile-time, měla by se přesunout alespoň co nejblíže místu vzniku chyby

Page 49: CZJUG –  21. února 2007

49/73

…Collections

● java.util.Collections<E>, pokračování– <T> void copy(List<? super T>, List<? extends T>)

– <T> List<T> emptyList()– <T extends Object &Comparable<? super T>>T max(Collection<? extends T>)

● Comparable<? super T> je ze stejného důvodu jako u binarySearch● mez Object je z důvodu binární kompatibility● bez Object by po erasure zbyloComparable max(),což by neodpovídalo původnímuObject max()

– void reverse(List<?>)● implementace používá raw typy● možná implementace použitím pomocné generické metody<T> void reverseHelper(List<T>)

Page 50: CZJUG –  21. února 2007

50/73

Class…

● java.lang.Class<T>– kompenzuje absenci runtime informace – pokud runtime

informaci potřebujeme, předáme Class<T>– parametrizovaná typem, který třída představuje, např. třída

řetězce "abc" je Class<String>– Class<? super T> getSuperclass()– T newInstance()– boolean isInstance(Object)

● runtime ekvivalent instanceof

– T cast(Object)● umožňuje přetypovat objekt na třídu, kterou známe v runtime, tak aby v

compile-time zůstala zachována schopnost zaručit typovou bezpečnost

public static <T> void filter(Class<T> clazz, List<?> src, List<T> dest) {for (Object o : src) {

if (clazz.isInstance(o)) dest.add(clazz.cast(o));}

}

Page 51: CZJUG –  21. února 2007

51/73

…Class

● java.lang.Class<T> (pokračování)– <U> Class<? extends U> asSubclass(Class<U>)– Class<?> forName(String)

● ?, ze Stringu nevíme nic

● java.lang.reflect.Constructor<T>● java.lang.Object

– Class<? extends Object> getClass()● dokumentace:● „Class<? extends X> where X is the erasure of the static type of the

expression on which getClass is called“

Number n = new Integer(1);Class<? extends Number> cn = (Class<? extends Number>)n.getClass();

Page 52: CZJUG –  21. února 2007

52/73

Ostatní

● třídy obalující referenci– java.lang.ThreadLocal<T>– java.lang.ref.Reference<T> a potomci

● java.util.concurrent● java.lang.Enum<E extends Enum<E>>

– může být parametrizován pouze podtypem● ne: class StringEnum extends Enum<String>

– potomek Enum je zároveň parametrem● ne: class DayOfWeek extends Enum<Color>

– pozn.: v protipříkladech ignorujeme jazykové opatření zabraňující přímému dědění z Enum

– potomek dědí metody, které závisejí na E● java.lang.reflect

Page 53: CZJUG –  21. února 2007

53/73

Praktické situace

● equals a spol.● kovariance● inference● návrhové vzory

Page 54: CZJUG –  21. února 2007

54/73

equals, clone a jiná drůbež…

● equals– jak porovnat Box<String> s Box<Integer> ?– nijak, typová informace není v runtime, je potřeba se

spolehnout na equals pro jednotlivé proměnné (které pro String a Integer vrátí false)

public static class Box<T> {private T value;public T getValue() {return value;}public void setValue(T value) {this.value = value;}@Overridepublic boolean equals(Object obj) {

if (!(obj instanceof Box)) return false;if (obj == this) return true;Box<?> that = (Box<?>)obj; // OKBox that = (Box)obj; // OKBox<T> that = (Box<T>)obj; // žádný přínos, unchecked warningBox<T> that = (Box<?>)obj; // errorreturn this.value.equals(that.value);

}...

Page 55: CZJUG –  21. února 2007

55/73

…equals, clone a jiná drůbež…

● clone– chceme vrátit stejný parametrizovaný typ, ale Object.clone() předepisuje návratový typ Object

● zúžíme návratový typ● warning u super.clone() ignorujeme

– o instančních proměnných typu T nevíme nic● Cloneable nám nepomůže, je to jen marker interface

(neovlivňuje API, nýbrž chování)● zbývá tedy „zkusmo“ vyvolat metodu clone, …

– ale narazíme na překážky:● clone je protected, nelze vyvolat přímo -> reflexe● metoda ve třídě nemusí být definována, třída není Cloneable, ale přesto to není důvod k selhání Box.clone() (immutable objekty)

– warning u přetypovávání (T) opět ignorujeme

Page 56: CZJUG –  21. února 2007

56/73

…equals, clone a jiná drůbež…

● clonepublic static class Box<T> implements Cloneable {

private T value;public T getValue() {return value;}public void setValue(T value) {this.value = value;}protected Box<T> clone() throws CloneNotSupportedException {

Box<T> retval = null;try {

retval = (Box<T>)super.clone(); // unchecked warning} catch (CloneNotSupportedException e) {

throw e;}try {

retval.value = (T)value.getClass().getMethod("clone",new Class[0]).invoke(value,new Object[0]);// unchecked warning

} catch (NoSuchMethodException e) {/* objekt nema metodu clone, ale promenna je immutable, * a proto nevadi melka kopie * (ta jiz byla provedena v super.clone()) */

} catch (Exception e) {throw new CloneNotSupportedException(e.getMessage());

}return retval;

}...

Page 57: CZJUG –  21. února 2007

57/73

…equals, clone a jiná drůbež…

● compareTo– má smysl pouze pokud typový parametr je Comparable

public static class Box<T> implements Comparable<Box<T>> {private T value;public T getValue() {return value;}public void setValue(T value) {this.value = value;}

public int compareTo(Box<T> that) {T thisValue = this.value;T thatValue = that.value;// zde se nic delat neda, nebot o T nevime nic nez ze je Objectthrow new Error();

}}

public static class CBox<T extends Comparable<T>> implements Comparable<Box<T>> {

.../**public int compareTo(Box<T> that) {

return this.value.compareTo(that.value);//tady uz je to lepsi, vymezili jsme T jako Comparable

}}

Page 58: CZJUG –  21. února 2007

58/73

…equals, clone a jiná drůbež…

● Comparable<T>– nelze Super implements Comparable<Super> a současně Sub implements Comparable<Sub> (důvod: erasure)

– možnosti:

● pouze Comparable<Super>– buď: Sub nepřekrývá compareTo(Super), potomci se

porovnávají jen jako Super– anebo: Sub překrývá compareTo(Super), pak se ale musí

povolit porovnání jen pro objekty přetypované na Sub● příklad: Date/Timestamp● nevýhoda: Sub nelze použít jako T extends Comparable<T>● nevýhoda: porušení symetrie:sup.compareTo(sub) projde, alesub.compareTo(sup) skončí výjimkou

Page 59: CZJUG –  21. února 2007

59/73

…equals, clone a jiná drůbež

● pouze Comparable<Sub>– nelze použít Super jako Comparable<Super>, což ale

zpravidla moc nevadí (např. Number)– problém se symetrií je odstraněn (zadarmo)

● Sub nedědí Super – kompozice– Joshua Bloch (57 zásad)

Page 60: CZJUG –  21. února 2007

60/73

Neexistující kovariance…

● pole– jsou kovariantní

● tj. pole předků je předkem pole potomků– udržují informaci o runtime typu svých prvků

● generické typy– nejsou kovariantní

● tj. dva typy, jejichž typové parametry jsou příbuzné, příbuzné nejsou

– neudržují informaci o runtime typu svých prvků

private static void test1() {Object[] ao = new String[] {"foo"};ao[0] = 1; // ArrayStoreException

}

Page 61: CZJUG –  21. února 2007

61/73

…Neexistující kovariance

● kdyby byly generické typy kovariantní, nešlo by:

● v tomto sledu příkazů se někde musel zavést zákaz● na řádku 4? pozdě! nechceme výjimku● na řádku 3? tak se to dělá u polí

– pozn: ekvivalent metody test1() vyjádřený g. typy

● -> na řádku 2 !

1 List<String> ls = new ArrayList<String>();2 List<Object> lo = ls;3 lo.set(1);4 String s = ls.get(1); // ClassCastException

private static void test2() {List<String> ls = new ArrayList<String>();ls.add("foo");List checked = Collections.checkedList(ls,String.class);List<Object> lo = checked; // abychom priklad prelozili,

// pomuzeme si prechodem pres raw typlo.set(0,1);

}

Page 62: CZJUG –  21. února 2007

62/73

Pole generických typů…

● iluze– List<String>[] al = new ArrayList<String>[2];

– napravo je zákaz a vlevo to radši ani nezkoušejte● proč je zakázáno vytvořit takové pole?

– pole provádí runtime check– ale v runtime překladač nezná konkrétní typový

argument● na levé straně přiřazení se ale pole uvést smí!?

– ale k ničemu to nevede– protože co by pak mělo být na pravé straně?

● už víme, že ne pole generických typů(přesně: musí tam být pole „reifiable“ typů)

Page 63: CZJUG –  21. února 2007

63/73

…Pole generických typů

private static void test3() {// 1. moznost: null - nezajimaveList<String>[] als1 = null;

// 2. moznost: raw typ - ale to umoznuje podvrhnout vetrelceList<String>[] als2 = new List[] {Arrays.asList(0)};als2[0].set(0,"foo"); // !!! ArrayStoreExceptionString s = als2[0].get(0); // !!! ClassCastException

// 3. moznost: negenericky podtyp - ale pak uz je lepsi jej pouzit // i pri staticke deklaraci,class StringList extends ArrayList<String> {}ArrayList<String>[] als3 = new StringList[1];als3[0] = new ArrayList<String>(); // !!! ArrayStoreException, // staticky muzeme, ale v rt to slehneals3[0] = new StringList(); // takze nakonec stejne muzeme jen takto// cili vyuzijeme pouze rozhrani predka, ale to prece potomek podporuje taky!ArrayList<String> element = als3[0];element.size();// pro vyuziti potomka musime pretypovat, takze to vyjde nastejno// jako bychom pouzili potomka rovnou ve staticke deklaraciStringList sl = (StringList)element;

}

Page 64: CZJUG –  21. února 2007

64/73

Generiky a design patterns…

● návrhové vzory (DP) jsou založeny na polymorfismu● pružnost DP = za běhu je možné podsouvat jiné objekty● x u generik se snažíme co nejvíce věcí postihnout za

překladu● je to jiný typ polymorfismu, který se na DP ne vždy hodí ● generiky ovlivnily několik návrhových vzorů, ale nelze

čekat velkou revoluci● generické návrhové vzory

– Foo extends Hoo<Foo>● Comparable

– Enum<E extends Enum<E>>● Enum● Node

– C++, více možností, curious recurring template

Page 65: CZJUG –  21. února 2007

65/73

…Generiky a design patterns…

● Iterátor– java.util.Iterator<E>– dobrý kandidát na generický typ, T next()

● Bridge– abstrakce se parametrizuje implementací– kód to spíš sváže, implementace nebude možné měnit za chodu– příklad:

● abstrakce: Table (CsvTable, SqlTable)● implementace: View (ViewEverything, PaginatedView)

Table table = new CsvTable(csvFile);View view = new Paginated(8,1);View view2 = new Everything();table.view = view2;table.render(); Table<Paginated> table = new CsvTable<Paginated>(csvFile);

View view = new Paginated(8,1);View view2 = new Everything();//table.view = view2; // Type mismatchtable.view = new Paginated(8,1);table.render();

Page 66: CZJUG –  21. února 2007

66/73

…Generiky a design patterns…

● Chain of responsibility– implementace pomocí konstruktoruChainElement(ChainElement successor)

– implementace zřetězením článků● g. typy mohou být využitelné pro vyjádření vazby mezi objekty článku● problém: uspořádaná mapa dvojic Class<T>, Cosi<T>; nelze pomocí java.util.Map, ale implementace je podobná DP chain

● Singleton– nevhodný

● naivní (nefunkční) implementace založená na:public static <T> getInstance()

● tzv. workaround založený na:

– rychle pryč!

public static class SingletonManager {private static Map<Class<?>,Object> table

= new HashMap<Class<?>,Object>();public static synchronized <T> T getInstance(Class<T> clazz) {

T instance = clazz.cast(table.get(clazz)); ...

Page 67: CZJUG –  21. února 2007

67/73

…Generiky a design patterns…

● Factory method– paralelní třídní hierarchie– klasická továrna s hierarchií produktů výhody generik moc

nevyužije● svázání factory s produktem – je chtěné?● zúžení typu návratové metody potomka

– výhody se projevují až u metod, které mají typový parametr jako parametr metody

– další využití – statická factory metoda● stále záleží na tom, jak je typově bezpečná prvotní informace, podle které

se rozliší typ vytvářené továrnypublic static abstract class Product {

public abstract void repair();}public static class Java60 extends Product {

public void repair() {System.out.println("uz aby byly Closures ;-)");

}}

Page 68: CZJUG –  21. února 2007

68/73

…Generiky a design patterns…public static abstract class Factory {

public abstract Product createProduct();public abstract void repairProduct(Product product);

}

public static class SunMicrosystemsInc extends Factory {public Java60 createProduct() {return new Java60();}@Override // CHYBA, ve skutecnosti neprekryva, ale pretezujepublic void repairProduct(Java60 product) {product.repair();}@Overridepublic void repairProduct(Product product) {

if (!(product instanceof Java60)) throw new IllegalArgumentException();

product.repair(); // nebo ((Java60)product).specifickeRozhrani()}

}//--------------------------------------------------------------------------public static abstract class Factory<T extends Product> {

public abstract T createProduct();public abstract void repairProduct(T product);

}

public static class SunMicrosystemsInc extends Factory<Java60> {public Java60 createProduct() {

return new Java60();}@Override // OKpublic void repairProduct(Java60 product) {

product.repair(); // nebo product.specifickeRozhrani()}

}

Page 69: CZJUG –  21. února 2007

69/73

…Generiky a design patterns…

● Visitor● Decorator● AbstractFactory● Template Method

Page 70: CZJUG –  21. února 2007

70/73

Co se nevešlo

● inference● generická metoda nebo wildcard?● jak poznat, že má být typ generický● overriding x overloading● bridge method - špeky● reflection

Page 71: CZJUG –  21. února 2007

71/73

Odkazy● SUN: http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html● SUN: http://java.sun.com/docs/books/tutorial/java/generics/index.html● SUN Generics forum: http://forum.java.sun.com/forum.jspa?forumID=316● Gilad Bracha: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf● Angelika Langer Generic FAQ:

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html● Brian Goetz:

http://www-128.ibm.com/developerworks/edu/j-dw-java-generics-i.html● Brian Goetz generic gotchas:

http://www-128.ibm.com/developerworks/java/library/j-jtp01255.html● kniha: Rudolf Pecinovský: Java 5.0 - Novinky jazyka a upgrade aplikací (Grada)● odkazy na zajímavé problémy, články, blogy:

– typová bezpečnost: http://fpl.cs.depaul.edu/Problem.java– přetížení g. metody:

http://forum.java.sun.com/thread.jspa?forumID=316&threadID=428464– Peter Ahé: http://blogs.sun.com/ahe/entry/inference_and_compound_types– http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid_1.html– http://www.artima.com/weblogs/viewpost.jsp?thread=117200

Page 72: CZJUG –  21. února 2007

72/73

Q & A

?

Page 73: CZJUG –  21. února 2007

73/73

Děkuji za pozornost!


Recommended