1 Parametrizované třídy Generics generické třídy JDK zavádí mimo jiné tzv. parametrizované třídy - generics
Úvod 2 podobnost se šablonami (templates) z C++ nejčastěji použité v oblasti knihoven kontejnerového typu běžný případ použití: List myintlist = new LinkedList(); myintlist.add(new Integer(0)); Integer x = (Integer) myintlist.iterator().next(); (); kompilárot pouze garantuje, že z iterátoru bude vrácen Object, je vyžadováno jeho přetypování
Úvod 3 parametrizované typy (generics) umožňují označit seznam jako vymezený (omezený) pouze pro zadaný typ (Java 5) upravená verze fragmentu programu: List<Integer> myintlist = new LinkedList<Integer> <Integer>(); myintlist.add(new Integer(O)); //2 Integer x = myintlist.iterator().next(); (); //3 popis specifikuje, že je to seznam pouze pro Integer, zapsáno List<Integer> říkáme, že List je generické rozhraní, které má typový parametr v našem případě Integer (parametrizované rozhraní)
Úvod 4 Běžný pohled: Integer z řádku 3 se přesunul jako typový parametr do řádku 1 velký rozdíl je v tom, že kompilátor ve druhém případě může kontrolovat správnost programu v době kompilace! specifikací je myintlist deklarovaný s typem List<Integer>, to říká něco o proměnné myintlist na rozdíl od přetypování, kteréříká, že programátor si myslí, že je něco pravdivé v konkrétném řádku kódu
Úvod 5 další výhodou této změny je zlepšenáčitelnost programů a jejich robustnost odolnost vůči chybám
Definování jednoduchého parametrizovaného typu 6 část definice rozhraní: public interface List <E> { void add(e x); Iterator<E> iterator(); public interface Iterator<E> { E next(); boolean hasnext(); <E> je deklarace formálních typových parametrů rozhraní List a Iterátor
Definování jednoduchého parametrizovaného typu 7 intuitivně si můžeme představit, že List<Integer> nahradí verzi List, kde E je zaměněno za Integer: public interface IntegerList { void add(integer x); Iterator<Integer> iterator(); je to užitečné, ale zavádějící, protože parametrizovaný typ List<Integer> nemá metody, které vypadají jako jeho rozšíření
Definování jednoduchého parametrizovaného typu 8 při vyvolání deklarace generického typu jsou všechny výskyty formálního typového parametru <E> nahrazeny skutečným typovým argumentem (v tomto případě Integer). deklarace generického typu je kompilována jednou pro všechny a převedena na jeden soubor se třídou podobně jako deklarace běžné třídy nebo rozhraní.
Definování jednoduchého parametrizovaného typu 9 Typové parametry jsou analogické běžným parametrům používaným v metodách a konstruktorech. Podobně jako metoda má formální parametry popisující typ hodnoty, má generická deklarace také formální typ parametrů. Když je vyvolaná generická deklarace, aktuální typ parametrů nahradí formální typ parametrů.
Generické třídy a podtřídy Generics and Subtypying 10 List<String> ls = new ArrayList<String>(); //1 List<Object> lo = ls; //2 v //2 je seznam řetězců seznamem objektů? is List of String List of Object není lo.add(new Object()); //3 String s = ls.get(0); //4 pokus přiřadit Object k // řet etězci Seznam řidičů můžeme považovat za seznam osob (řidič je podtřídou osoby), pak je ale možné přidat další osoby bez ŘP do seznamu řidičů
Generické třídy a podtřídy Generics and Subtypying 11 rutina, která tiskne prvky kolekce (předchozí verze): void printcollection(collection c) { Iterator i = c.iterator(); for(k=0; k< c.size(); k++) { System.out.println(i.next()); ()); Java 5 verze void printcollection(collection<object> c) { for(object e : c) { System.out.println(e); Collection<Object> není nadtřídou všech kolekcí!
Generické třídy a podtřídy Generics and Subtypying 12 využití typu wildcard; co je nadtřídou všech typů kolekcí? Collection<?> kolekce neznámých typů vyhovuje všem typům void printcollection(collection Collection<?> c) { for (Object e : c) { // popis Object správn vně není správné: System.out.println(e); Collection<?> c = new ArrayList<String>(); c.add(new Object()); // chyba kompilace c může obsahovat pouze řetězce
public abstract class Shape { public abstract void draw(canvas c); public class Circle extends Shape { private int x, y; radius; public void draw(canvas c) {... public class Rectangle extends Shape { private int x, y, width, height; public void draw(canvas c) {... Outline Bounded wildcards 13 public class Canvas { public void draw(shape s) { s.draw(this); public void drawall(list<shape> shapes) { for ( Shape s : shapes) { s.draw(this); // funguje jen pro typ Shape, ne pro jeho instance!!
Bounded Wildcard 14 provedeme změnu: public void drawall(list<? extends Shape> shapes) {... malý, ale významný rozdíl, List<Shape> je zaměněn za List<? extends Shape> nyní metoda drawall() akceptuje seznamy libovolné podtřídy třídy Shape, takže ji můžeme zavolat např. na List<Circle> List<? extends Shape> - je příkladem tzv. bounded wildcard? představuje neznámý typ podobně jako wildcard
Bounded Wildcard 15 Neznámý typ může být Shape, nebo podtřída, říkáme, že Shape je upper bound of wildcard horní hranice cena za toto rozšíření je ztráta možnosti zapisovat do shapes v tělech metod např.: public void addrectangle(list List<? extends Shape> shapes) { shapes.add(0, new Rectangle()); ); // compile time error typ druhého parametru metody shapes.add() ne neznámým podtypem typu Shape. Protože nevíme, jaký je to typ, nevíme, zda-li to není nadtyp typu Rectangle, takže není bezpečné tam vkládat objekty Rectangle