Metody sparametryzowane Nie tylko klasy i pola można parametryzować. Parametry typu można zastosować również do pojedynczych metod. Podstawienie typu zostanie wykonane podczas wywołania metody. class Box { public static <T> int zrobobiekt(t a){ System.out.println("cos " +a.tostring()); return 0; } public static <T extends Number> T zrobnumer(t a){ System.out.println("numer "+ a.intvalue()); return a; } } Podczas wywołania sprawdzone zostaną typy i metoda zrobnumer zwróci obiekt takiego samego typu jak otrzymany w argumencie. Jest to wnioskowanie typów (ang. type inference). package test24a
Metody sparametryzowane Nie tylko klasy i pola można parametryzować. Parametry typu można zastosować również do pojedynczych metod. Podstawienie typu zostanie wykonane podczas wywołania metody. Integer a = Box.zrobNumer(new Integer(1)); Number b = Box.zrobNumer(new Integer(2)); Integer c = Box.zrobNumer(new Number(3)); Box.zrobObiekt(new Integer(4)); Zwrot tego samego typu Zwrot tego samego typu z przypisaniem do nadtypu Nie można skonwertować do typu węższego Box.zrobNumer("bum"); int d = Box.zrobObiekt("bum"); Sprawdzenie typu: String nie rozszerza Number package test24a
Szablony klas parametry uniwersalne Czasem wymagane jest aby można było korzystać z możliwości dziedziczenia klas sparametryzowanych. Ponieważ po kompilacji wszystkie typy stają się surowe nie da się zapewnić, że będzie zgodność zarówno klas jak ich parametrów. Box<Integer> extends Box<Number> Wprowadzono zatem parametry uniwersalne? (wildcards). Dzięki temu można - zastosować ograniczenie górne: - dowolny podtyp A <? extends A> - zastosować ograniczenie dolne: - dowolny nadtyp A <? super A> - zastosować pełną dowolność: dowolny typ <?> Box<Integer> extends Box<? extends Number> Box<? super Integer> extends Box<Number> Box<Integer> extends Box<?>
Parametry uniwersalne - przypisanie Dzięki parametrom uniwersalnym można tworzyć zmienne będące w stanie przechowywać obiekty z różnymi typami. Box<String> s = new Box<String>("aaa"); Box<Integer> i = new Box<Integer>(3); Box<Number> n = new Box<Number>(3); Box bs = s; Box bi = i; Box bn = n; Box<?> us = s; Box<?> ui = i; Box<?> un = n; Box<? extends String> ess = s; Box<? extends String> esi = i; // Integer nie rozszerza String Box<? extends String> esn = n; // Number nie rozszerza String Box<? extends Integer> eis = s; // String nie rozszerza Integer Box<? extends Integer> eii = i; Box<? extends Integer> ein = n; // Number nie rozszerza Integer Box<? extends Number> ens = s; // String nie rozszerza Number Box<? extends Number> eni = i; Box<? extends Number> enn = n; Box<? super Number> sni = i; // Integer jest nadklasą Number Box<? super Number> snn = n; Box<? super Integer> sii = i; Box<? super Integer> sin = n; Typ elementu jawny Typ surowy Wildcard dowolny Typ rozszerza String Typ rozszerza Integer Typ rozszerza Number Typ jest z nadklasy Number Typ jest z nadklasy Integer package test25a
Parametry uniwersalne - użyteczność Dzięki parametrom uniwersalnym można tworzyć zmienne będące w stanie przechowywać obiekty z różnymi typami. Box<String> s Box<Integer> i Box<Number> n Box bs Box bi Box bn Box<?> us Box<?> ui Box<?> un Box<? extends String> ess s.getelement().touppercase(); i.getelement().bitcount(0); n.getelement().intvalue(); bs.getelement().touppercase(); bi.getelement().bitcount(0); bn.getelement().intvalue(); us.getelement().touppercase(); ui.getelement().bitcount(0); un.getelement().intvalue(); ess.getelement().touppercase(); Metody każdej z klas Tylko metody klasy Object Eclipse zgłasza ostrzeżenie Tylko metody klasy Object Tak jak typ surowy, ale brak ostrzeżenia Metody z klasy String Box<? extends Integer> eii Box<? extends Number> eni Box<? extends Number> enn Box<? super Number> snn Box<? super Integer> sii Box<? super Integer> sin eii.getelement().bitcount(0); eni.getelement().bitcount(0); eni.getelement().intvalue(); enn.getelement().intvalue(); snn.getelement().intvalue(); sii.getelement().bitcount(0); sin.getelement().intvalue(); Metody z klasy Integer Metody z klasy Number Tylko metody klasy Object Tylko metody klasy Object package test25a
Parametry uniwersalne ograniczone Niech dana będzie funkcja kopiująca obiekt ze źródła do celu w jakimś pudełku public static void copy(box<...> src, Box<...> dest){ dest.setelement(src.getelement()); }; Należy nadać jej argumentom typ. Aby działało dla każdego typu obiektu można zrobić tak: public static void copy(box<?> src, Box<?> dst){...}; Ale w tym przypadku można by było wywołać tą metodę Box.copy(new Box<Integer>(1), new Box<String>( bum ); i byłby błąd przypisania typów, ponieważ src.getelement() zwróci typ Integer, a dest.setelement() oczekuje String.
Parametry uniwersalne ograniczone Musimy zapewnić, żeby dało się przypisać typy. Zmienna, która będzie czytana powinna mieć ustawione ograniczenie dolne - extends Zmienna, do której będą przypisania powinna mieć ustawione ograniczenie górne - super public static void copy(box<? extends Number> src, Box<? super Number> dst) Źródło rozszerza Number (np. Number, Integer, Double), a cel jest jego nadklasą (np. Number, Object). Dzięki temu zawsze będzie możliwe przypisanie. public static void copy(box<? extends Integer> src, Box<? super Integer> dst) Źródło rozszerza Integer, a cel jest jego nadklasą (np. Integer,Number,Object) public static void copy(box<? extends Integer> src, Box<? super Number> dst) Źródło rozszerza Integer, a cel jest jego nadklasą Number (np. Number,Object) package test26a
Parametry uniwersalne ograniczone copy1 Box<? extends Integer> src Box<? super Integer> dst copy2 Box<? extends Number> src Box<? super Number> dst copy3 Box<? extends Integer> src Box<? super Number> dst copy4 Box<? extends Number> src Box<? super Object> dst src: Integer src: Integer,Number src: Integer src: Integer,Number dst: Integer, Number, Object dst: Number, Object dst: Number, Object dst: Object Box.copy1(i1,i2); Box.copy1(n1,n2); Box.copy1(o1,o2); Box.copy1(n1,i2); Box.copy1(i1,n2); Box.copy1(o1,i2); Box.copy1(o1,n2); Box.copy1(i1,o2); Box.copy1(n1,o2); Box.copy2(i1,i2); Box.copy2(n1,n2); Box.copy2(o1,o2); Box.copy2(n1,i2); Box.copy2(i1,n2); Box.copy2(o1,i2); Box.copy2(o1,n2); Box.copy2(i1,o2); Box.copy2(n1,o2); Box.copy3(i1,i2); Box.copy3(n1,n2); Box.copy3(o1,o2); Box.copy3(n1,i2); Box.copy3(i1,n2); Box.copy3(o1,i2); Box.copy3(o1,n2); Box.copy3(i1,o2); Box.copy3(n1,o2); Box.copy4(i1,i2); Box.copy4(n1,n2); Box.copy4(o1,o2); Box.copy4(n1,i2); Box.copy4(i1,n2); Box.copy4(o1,i2); Box.copy4(o1,n2); Box.copy4(i1,o2); Box.copy4(n1,o2); package test26a
Parametry uniwersalne ograniczone Nie można dać zbytniej dowolności typów public static void copy(box<? extends Number> src, Box<? super Integer> dst) ponieważ w tym przypadku nie można zapewnić że podtyp Number będzie nadtypem Integera np. możemy dać src typu Double. Dzięki górnemu ograniczeniu (extends) możemy korzystać z metod klasy ograniczającej. Dzięki dolnemu ograniczeniu (super) możemy korzystać tylko z metod klasy Object, ale za to możemy przypisywać tym obiektom więcej typów. W zmiennych które mają służyć zarówno do czytania jak i przypisywania nie stosuje się symboli wieloznacznych. package test26a
Szablony klas Ćwiczenie 14a. Mając dane klasy Czytelnik, Pracownik i Student, zaimplementuj metodę sparametryzowaną w klasie Czytelnik, dzięki, której będzie można wypisać na konsolę dane z listy czytelników.
Kolekcje Ćwiczenie 15a. Zaimplementuj w klasie Książka kolekcję do przechowywania kolejki rezerwacji czytelników. Utwórz metody pozwalające na wypożyczenie książki czytelnikowi z kolejki, kiedy tylko zostanie ona oddana. Utwórz także kolekcję przechowującą wypożyczone książki u Czytelnika i dodaj metody rezerwowania i oddawania książek.