Title: Wybrane elementy jezyka Java
1Wybrane elementy jezyka Java ciag dalszy
2- Wyjatki
- Reflection
- Tworzenie i zarzadzanie obiektami
- Garbage Collector i finalize()
- Nowe elementy Javy 1.5
- Typy sparametryzowane
- Covariant return types
- autoboxing
- Petla w stylu foreach
- Bezpieczne (type-safe) enumeracje
- Statyczne import
- Metody ze zmienna liczba parametrów
3- Wyjatki
- Reflection
- Tworzenie i zarzadzanie obiektami
- Garbage Collector i finalize()
- Nowe elementy Javy 1.5
- Typy sparametryzowane
- Covariant return types
- autoboxing
- Petla w stylu foreach
- Bezpieczne (type-safe) enumeracje
- Statyczne import
- Metody ze zmienna liczba parametrów
4Typy sparametryzowane
- Obecne w np. C
- Uzywane najczesciej w kontekscie róznych operacji
na kolekcjach - W Javie 1.4 (i wczesniejszych) musimy uzywac
rzutowania - List myIntList new LinkedList()
- myIntList.add(new Integer(0))
- Integer x (Integer) myIntList.iterator().next()
- aby zapewnic poprawnosc typów w czasie
wykonania. Kompilator wie jedynie, ze obiekt typu
LinkedList przechowuje elementy typu Object - Uzycie generics w Javie 1.5
- ListltIntegergt myIntList new LinkedListltIntegergt(
) - myIntList.add(new Integer(0))
- Integer x myIntList.iterator().next()
5Typy sparametryzowane - skladnia
- Deklaracja uzywamy formalnego parametru typu,
np. - public interface ListltEgt
- void add(E x)
- IteratorltEgt iterator()
-
- Wywolanie typ sparametryzowany, np.
- List ltIntegergt myList
- intuicyjne rozumienie wywolania kazde
wystapienie formalnego parametru typu w
deklaracji typu sparametryzowanego zastepujemy
faktycznym parametrem typu, np. zastepujemy we
wszystkich metodach ListltEgt wystapnienia E typem
Integer - W rzeczywistosci, skompilowany kod typu
sparametryzowanego istnieje tylko w jednej kopii
(jeden plik klasy .class)
6Typy sparametryzowane - wildcards
- Jak napisac metode wypisujaca wszystkie elementy
kolekcji? - void printCollection(CollectionltObjectgt c) for
(Object e c) System.out.println(e) - (uzywamy dodatkowo nowej postaci petli for)
- Skoro CollectionltObjectgt nie jest nadtypem innej
sparametryzowanej kolekcji, musielibysmy stworzyc
odpowiednie metody do wypisywania elementów
CollectionltStringgt etc. - Collectionlt?gt jest nadtypem wszystkich kolekcji.
? Jest typem wildcard - void printCollection(Collectionlt?gt c) for
(Object e c) System.out.println(e)
7Typy sparametryzowane bounded wildcards
- Nawet jesli Shape jest nadtypem Circle, Rectangle
etc., ListltShapegt nie jest nadtypem ListltCirclegt,
ListltRectanglegt - Mozemy jawnie zadeklarowac tzw. upper bound
parametru typu - List lt? extends Shapegt
8Typy sparametryzowane implementacja, erasure
- Problem uzywania kodu generics z kodem
wczesniejszych wersji Javy - public String loophole(Integer x)
- ListltStringgt ys new LinkedListltStringgt
- List xs ys
- xs.add(x)
- ys.iterator().next()
-
- Jak we wczesniejszym przykladzie, tworzymy alias
xs do zmiennej ys typu spararametryzowanego
ListltStringgt - Tutaj kod sie kompiluje (kompilator daje jedynie
ostrzezenie), natomiast uzycie blednego typu daje
blad wykonania (ClassCastException) - return (String) ys.iterator().next()
- Implementacja generics dziala jako przód
(front-end) normalnego kompilatora Javy, kod z
uzyciem generics jest zamieniany na normalny
bytecode Javy w trakcie procesu nazwanego erasure
9Typy sparametryzowane implementacja, erasure
- Kod sparametryzowany
- public String loophole(Integer x)
- ListltStringgt ys new LinkedListltStringgt
- List xs ys
- xs.add(x)
- ys.iterator().next()
-
- zostanie przetlumaczony do
- public String loophole(Integer x) List ys new
LinkedList - List xs ys
- xs.add(x)
- return (String) ys.iterator().next() // run time
error -
- Podwójna kontrola typów
- translator sprawdza poprawnosc uzycia typów
sparametryzowanych (np. nie moglibysmy
zadeklarowac ListltObjectgt xs) - Do wynikowego kodu zwyklej Javy dodawane sa
rzutowania wszedzie, gdzie moze wystapic
niepoprawne (pod wzgl. typów) przypisanie
10Typy sparametryzowane - erasure
- Mechanizm polega na mapowaniu typów
sparametryzowanych do typów niesparametryzowanych - Erasure klasy niesparametryzowanej nie zmienia
definicji tej klasy - Typy sparametryzowane traca typ parametru
- TreeltTgt ? Tree
- TreeltIntegergt ? Tree
- Typ parametru jest mapowany do swojego upper
bound - T (w klasie Tree) ? Object
- ale
- Bush ltT extends Colorgt
- T (w klasie Bush) ? Color
- Wstawiane sa odpowiednie rzutowania
11Typy sparametryzowane - erasure
- Czy skopiluje sie
- class ShoppingCartltT extends DVDgt
- // ...
-
- class ShoppingCartltT extends VideoTapegt
- // ...
-
- ?
- Nie po erasure, obie klasy mialyby ta sama nazwe
12Typy sparametryzowane - erasure
- Czy skompiluje sie
- class TwoForOneSpecialltT extends Rentable, W
extends Rentablegt - public void add(T newRentable)
- //...
-
- public void add(W newRentable)
- //...
-
- ?
- Nie po erasure, obie metody maja te same
sygnatury
13Typy sparametryzowane - erasure
- Czy skompiluje sie
- class GetAFreeVideoTapeltT extends Rentable, W
extends VideoTapegt - public void add(T anything)
- //...
-
- public void add(W videotape)
- //...
-
-
- ?
- Tak po erasure dostaniemy kod odpowiadajacy
- class GetAFreeVideoTape
- public void add(Rentable anything)
- //...
-
- public void add(Videotape videotape)
- //...
-
14Typy sparametryzowane jeden kod klasy
- Dlaczego nie jest poprawna konstrukcja
- class MyClassltTgt
- static T member
-
- ?
- Tworzac wiele instancji typu sparametryzowanego,
np. - MyClassltIntegergt myIntClass
- MyClassltStringgt myStringClass
- mielibysmy tylko jedna kopie member w pamieci.
Jakiego typu bylaby ta zmienna?
15Typy sparametryzowane jeden kod klasy
- Jaki wynik da wykonanie
- List ltStringgt l1 new ArrayListltStringgt()
- ListltIntegergt l2 new ArrayListltIntegergt()
- System.out.println(l1.getClass()
l2.getClass()) - ?
- Poniewaz kod z uzyciem generics i tak jest
tlumaczony do kodu bez typów sparametryzowanych,
wszystkie instancje klas sparametryzowanych sa
tej samej klasy - true
16Typy sparametryzowane i dziedziczenie
- Fragment kodu
- ListltStringgt ls new ArrayListltStringgt()
- ListltObjectgt lo ls
- daje blad kompilacji w linii 2
- Intuicyjne rozumienie ListltObjectgt jako nadtypu
ListltStringgt nie jest poprawne! Rozwazajac - lo.add(new Object())
- String s ls.get(0)
- Wczesniej stworzylismy alias do obiektu lo o
nazwie ls - W pierwszej linii wstawiamy do listy element typu
Object nie ma juz gwarancji, ze lista
przechowuje elementy wylacznie typu String - Jesli caly kod kompilowalby sie, druga linia nie
zachowywalaby poprawnosci typów - Ogólnie, mimo iz
- A extends B
- to jednak ListltBgt nie jest podtypem ListltAgt
17- Wyjatki
- Reflection
- Tworzenie i zarzadzanie obiektami
- Garbage Collector i finalize()
- Nowe elementy Javy 1.5
- Typy sparametryzowane
- Covariant return types
- autoboxing
- Petla w stylu foreach
- Bezpieczne (type-safe) enumeracje
- Statyczne import
- Metody ze zmienna liczba parametrów
18Covariant return types
- Do wersji 1.4 jezyka przeslaniajaca
implementowana w nadklasie metoda podklasy
musiala miec identyczna sygnature w
szczególnosci, zwracany typ - Ponizszy kod nie kompiluje sie w JRE 1.4.1_02
- class Fruit implements Cloneable
- Fruit copy() throws CloneNotSupportedException
return (Fruit) clone() -
- class Apple extends Fruit implements Cloneable
- Apple copy() throws CloneNotSupportedException
return (Apple) clone() -
- Wywolujac clone() na obiekcie Apple dostajemy
obiekt nadklasy Fruit i musimy niepotrzebnie
rzutowac w dól do Apple - Java 1.5 dopuszcza taka konstrukcje
19- Wyjatki
- Reflection
- Tworzenie i zarzadzanie obiektami
- Garbage Collector i finalize()
- Nowe elementy Javy 1.5
- Typy sparametryzowane
- Covariant return types
- autoboxing
- Petla w stylu foreach
- Bezpieczne (type-safe) enumeracje
- Statyczne import
- Metody ze zmienna liczba parametrów
20Iterowanie po elementach kolekcji
- Dotychczas (Java 1.4) uzywamy konstrukcji typu
- public void drawAll (Collection c)
- Iterator itr c.iterator()
- while (itr.hasNext())
- ((Shape)itr.next()).draw()
-
-
- Uzywajac typów parametrycznych, mozemy
zaoszczedzic sobie kodowania kilku rzutowan - public void drawAll (CollectionltShapegt c)
- IteratorltShapegt itr c.iterator()
- while (itr.hasNext())
- itr.next().draw()
-
-
21Petla foreach generics
- Nowa dopuszczalna postac petli for
- public void drawAll(CollectionltShapegt c)
- for (Shape sc)
- s.draw()
-
- Rozwijane automatycznie do kodu
- for (IteratorltShapegt i c.iterator()
i.hasNext()) - Shape s i.next()
- s.draw()
22- Wyjatki
- Reflection
- Tworzenie i zarzadzanie obiektami
- Garbage Collector i finalize()
- Nowe elementy Javy 1.5
- Typy sparametryzowane
- Covariant return types
- autoboxing
- Petla w stylu foreach
- Bezpieczne (type-safe) enumeracje
- Statyczne import
- Metody ze zmienna liczba parametrów
23Bezpieczne (type-safe) typy wyliczeniowe
- Typ wyliczeniowy obecny w C, C, C, Pascalu
- Dotychczas
- public class Karty
-
- public static final int PIK 0
- public static final int TREFL 1
- public static final int KARO 2
- public static final int KIER 3
-
- Uzycie wzorca (pattern) zamiast konstrukcji
jezyka - Potencjalne problemy
- Metoda oczekujaca Karty skompiluje sie nawet,
jesli jako parametr przekazemy literal np. 5 - Optymalizacja przez kompilator inlining
24Typy wyliczeniowe - inlining
- Kompilator optymalizuje kod binarny wlaczajac
wartosci stalych bezposrednio do kazdej klasy,
która ich uzywa - Zgodnie ze specyfikacja jezyka, narzedzia moga,
ale nie musza wspierac model rozproszonej pracy
nad aplikacja i automatycznie rekompilowac klasy
uzywane przez program - public class Test
-
- public Test()
-
-
- static public void main(String args)
-
- System.out.println(Karty.KARO)
-
-
- Po zrekompilowaniu klasy Karty i zmianie wartosci
stalej KARO uruchomienie klasy Test (poza IDE) da
rezutat identyczny jak przed zmiana stalej
25Typy wyliczeniowe wzorzec typesafe enum
- Zdefiniuj klase reprezentujaca pojedynczy element
typu wyliczeniowego (UWAGA system typów Javy
1.4 nie obejmuje typu wyliczeniowego) - Nie udostepniaj zadnych publicznych konstruktorów
- Jedynie pola public static final
- Nigdy nie stworzymy obiektów tego typu poza tymi
udostepnianymi przez pola public static final - public class KartyPattern
-
- public final String nazwa
- private KartyPattern(String nazwa) this.nazwa
nazwa - public String toString() return nazwa
- public static final KartyPattern PIK new
KartyPattern("pik") - public static final KartyPattern TREFL new
KartyPattern("trefl") - public static final KartyPattern KARO new
KartyPattern("karo") - public static final KartyPattern KIER new
KartyPattern("kier")
26Typy wyliczeniowe wzorzec typesafe enum
- Uzycie wzorca typesafe enum gwarantuje poprawnosc
wykonania (runtime) - Jesli zdefiniujemy metode oczekujaca parametru
typu KartyPattern mamy pewnosc, ze kazda
niezerowa (non-null) referencja przekazana do tej
metody reprezentuje poprawny kolor karty - Stale moga byc dodane do takiej klasy bez
rekompilowania klas-klientów - Stale nigdy nie sa wkompilowane do klas ich
uzywajacych (klientów) - Mozemy zmienic metode toString() aby uzyskac
sensowna reprezentacje stalych na ekranie - Porównywanie stalych odbywa sie przez
dziedziczona z Object metode equals wykonujaca
porównanie referencji, a nie np. kosztowne
porównywanie Stringów - Wady
- Klasy J2SE i APIs produktów opartych na Javie
rzadko uzywaja wzorca typesafe enum, jest on
generalnie malo popularny - Kod znacznie sie rozrasta, jesli chcemy dodac
serializacje klasy, uporzadkowanie wartosci etc.
27Wzorzec typesafe enum problemy z serializacja
- Dodajemy
- public class KartyPattern implements Serializable
- Ponizszy kod
- ByteArrayOutputStream bout new
ByteArrayOutputStream () - ObjectOutputStream out new
ObjectOutputStream (bout) - KartyPattern kp KartyPattern.KARO
- out.writeObject (kp)
- out.flush ()
- ByteArrayInputStream bin new
ByteArrayInputStream (bout.toByteArray ()) - ObjectInputStream in new ObjectInputStream
(bin) - KartyPattern kp2 (KartyPattern)
in.readObject () - System.out.println ((kp2 KartyPattern.KARO
kp2 KartyPattern.KIER - kp2 KartyPattern.PIK kp2
KartyPattern.TREFL)) - Wypisuje
- False
- W klasie implementujacej Serializable
musielibysmy przeslonic metode readResolve(),
zeby upewnic sie, ze podczas deserializacji nie
zostanie stworzona nowa instancja klasy, a uzyte
bedzie stworzone wczesniej statyczne pole..
28Typy wyliczeniowy w Java 1.5
- Wbudowany w specyfikacje jezyka nowy typ
wyliczeniowy (enum) - enum Karta (pik, trefl, karo, kier)
- W odróznieniu od klas wzorca typesafe enum,
zmienne takiego typu moga byc uzywane w klauzuli
switch - Karta karta
- switch karta
- case Karta.pik ...
-
- Nie sa konieczne zmiany JVM
- Implementowane przez kompilator
- Nowa klasa java.lang.Enum, po której dziedzicza
wszystkie zmienne typu wyliczeniowego - Deklaracja jest nowym rodzajem deklaracji klasy
- W szczególnosci, nie jest legalne jawne tworzenie
instancji enumeracji przy uzyciu new()
29Typy wyliczeniowy w Java 1.5
- A Typesafe Enum Facility for the Javatm
Programming Language - http//www.jcp.org/aboutJava/communityprocess/jsr/
tiger/enum.html - Effective Java Programming Substitutes for
Missing C Constructs - http//java.sun.com/developer/Books/shiftintojava/
page1.htmlreplaceenums - Typesafe Enum Using enum in J2SE 1.5 (Tiger)
- http//www.langrsoft.com/articles/enum.html
- Beware of Java typesafe enumerations
- http//www.javaworld.com/javaworld/javatips/jw-jav
atip122.html
30Literatura i URLs
- Wprowadzenie do uzycia Generics
- http//developer.java.sun.com/developer/technicalA
rticles/releases/generics/ - The Java Language Specification, dostepna z
java.sun.com