1 Wybrane elementy języka Java – ciąg dalszyPaweł Zdziarski
2 Wyjątki Reflection Tworzenie i zarządzanie obiektamiGarbage Collector i finalize() Nowe elementy Javy 1.5 Typy sparametryzowane Covariant return types „autoboxing” Pętla w stylu foreach Bezpieczne (type-safe) enumeracje Statyczne import Metody ze zmienną liczbą parametrów
3 Tworzenie i zarządzanie obiektami Garbage Collector i finalize() Wyjątki Reflection Tworzenie i zarządzanie obiektami Garbage Collector i finalize() Nowe elementy Javy 1.5 Typy sparametryzowane Covariant return types „autoboxing” Pętla w stylu foreach Bezpieczne (type-safe) enumeracje Statyczne import Metody ze zmienną liczbą parametrów
4 Typy sparametryzowaneObecne w np. C++ Używane najczęściej w kontekście różnych operacji na kolekcjach W Javie 1.4 (i wcześniejszych) musimy używać rzutowania List myIntList = new LinkedList(); myIntList.add(new Integer(0)); Integer x = (Integer) myIntList.iterator().next(); aby zapewnić poprawność typów w czasie wykonania. Kompilator wie jedynie, że obiekt typu LinkedList przechowuje elementy typu Object Użycie generics w Javie 1.5 List
5 Typy sparametryzowane - składniaDeklaracja: używamy formalnego parametru typu, np. public interface List
6 Typy sparametryzowane - wildcardsJak napisać metodę wypisującą wszystkie elementy kolekcji? void printCollection(Collection (używamy dodatkowo nowej postaci pętli for) Skoro Collection Collection> jest nadtypem wszystkich kolekcji. ? Jest typem wildcard void printCollection(Collection> c) { for (Object e : c) { System.out.println(e);}}
7 Typy sparametryzowane – bounded wildcardsNawet jeśli Shape jest nadtypem Circle, Rectangle etc., List
8 Typy sparametryzowane – implementacja, erasureProblem używania kodu generics z kodem wcześniejszych wersji Javy public String loophole(Integer x) { List
9 Typy sparametryzowane – implementacja, erasureKod sparametryzowany public String loophole(Integer x) { List
10 Typy sparametryzowane - erasureMechanizm polega na mapowaniu typów sparametryzowanych do typów niesparametryzowanych Erasure klasy niesparametryzowanej nie zmienia definicji tej klasy Typy sparametryzowane tracą typ parametru Tree
11 Typy sparametryzowane - erasureCzy skopiluje się class ShoppingCart
12 Typy sparametryzowane - erasureCzy skompiluje się class TwoForOneSpecial
13 Typy sparametryzowane - erasureCzy skompiluje się class GetAFreeVideoTape
14 Typy sparametryzowane – jeden kod klasyDlaczego nie jest poprawna konstrukcja class MyClass
15 Typy sparametryzowane – jeden kod klasyJaki wynik da wykonanie List
16 Typy sparametryzowane i dziedziczenieFragment kodu List
17 Tworzenie i zarządzanie obiektami Garbage Collector i finalize() Wyjątki Reflection Tworzenie i zarządzanie obiektami Garbage Collector i finalize() Nowe elementy Javy 1.5 Typy sparametryzowane Covariant return types „autoboxing” Pętla w stylu foreach Bezpieczne (type-safe) enumeracje Statyczne import Metody ze zmienną liczbą parametrów
18 Covariant return typesDo wersji 1.4 języka przesłaniająca implementowaną w nadklasie metoda podklasy musiała mieć identyczną sygnaturę – w szczególności, zwracany typ Poniższy kod nie kompiluje się 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(); Wywołując clone() na obiekcie Apple dostajemy obiekt nadklasy Fruit i musimy niepotrzebnie rzutować w dół do Apple Java 1.5 dopuszcza taką konstrukcję
19 Tworzenie i zarządzanie obiektami Garbage Collector i finalize() Wyjątki Reflection Tworzenie i zarządzanie obiektami Garbage Collector i finalize() Nowe elementy Javy 1.5 Typy sparametryzowane Covariant return types „autoboxing” Pętla w stylu foreach Bezpieczne (type-safe) enumeracje Statyczne import Metody ze zmienną liczbą parametrów
20 Iterowanie po elementach kolekcjiDotychczas (Java 1.4) używamy konstrukcji typu public void drawAll (Collection c) { Iterator itr = c.iterator(); while (itr.hasNext()) { ((Shape)itr.next()).draw(); } Używając typów parametrycznych, możemy zaoszczędzić sobie kodowania kilku rzutowań public void drawAll (Collection
21 Pętla „foreach” + genericsNowa dopuszczalna postać pętli „for” public void drawAll(Collection
22 Tworzenie i zarządzanie obiektami Garbage Collector i finalize() Wyjątki Reflection Tworzenie i zarządzanie obiektami Garbage Collector i finalize() Nowe elementy Javy 1.5 Typy sparametryzowane Covariant return types „autoboxing” Pętla w stylu foreach Bezpieczne (type-safe) enumeracje Statyczne import Metody ze zmienną liczbą parametrów
23 Bezpieczne (type-safe) typy wyliczenioweTyp 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; } Użycie wzorca (pattern) zamiast konstrukcji języka Potencjalne problemy Metoda oczekująca Karty skompiluje się nawet, jeśli jako parametr przekażemy literał np. 5 Optymalizacja przez kompilator – inlining
24 Typy wyliczeniowe - inliningKompilator optymalizuje kod binarny włączając wartości stałych bezpośrednio do każdej klasy, która ich używa Zgodnie ze specyfikacją języka, narzędzia mogą, ale nie muszą wspierać model rozproszonej pracy nad aplikacją i automatycznie rekompilować klasy używane przez program public class Test { public Test() } static public void main(String[] args) System.out.println(Karty.KARO); Po zrekompilowaniu klasy Karty i zmianie wartości stałej KARO uruchomienie klasy Test (poza IDE) da rezutat identyczny jak przed zmianą stałej
25 Typy wyliczeniowe – wzorzec typesafe enumZdefiniuj klasę reprezentującą pojedynczy element „typu wyliczeniowego” (UWAGA: system typów Javy 1.4 nie obejmuje typu wyliczeniowego) Nie udostępniaj żadnych publicznych konstruktorów Jedynie pola public static final Nigdy nie stworzymy obiektów tego typu poza tymi udostępnianymi 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"); }
26 Typy wyliczeniowe – wzorzec typesafe enumUżycie wzorca typesafe enum gwarantuje poprawność wykonania (runtime) Jeśli zdefiniujemy metodę oczekującą parametru typu KartyPattern mamy pewność, że każda niezerowa (non-null) referencja przekazana do tej metody reprezentuje poprawny kolor karty Stałe mogą być dodane do takiej klasy bez rekompilowania klas-klientów Stałe nigdy nie są wkompilowane do klas ich używających (klientów) Możemy zmienić metodę toString() aby uzyskać sensowną reprezentację stałych na ekranie Porównywanie stałych odbywa się przez dziedziczoną z Object metodę equals wykonującą porównanie referencji, a nie np. kosztowne porównywanie String’ów Wady: Klasy J2SE i API’s produktów opartych na Javie rzadko używają wzorca typesafe enum, jest on generalnie mało popularny Kod znacznie się rozrasta, jeśli chcemy dodać serializację klasy, uporządkowanie wartości etc.
27 Wzorzec typesafe enum – problemy z serializacjąDodajemy public class KartyPattern implements Serializable Poniższy 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 implementującej Serializable musielibyśmy przesłonić metodę readResolve(), żeby upewnić się, że podczas deserializacji nie zostanie stworzona nowa instancja klasy, a użyte będzie stworzone wcześniej statyczne pole..
28 Typy wyliczeniowy w Java 1.5Wbudowany w specyfikację języka nowy typ: wyliczeniowy (enum) enum Karta (pik, trefl, karo, kier); W odróżnieniu od klas wzorca typesafe enum, zmienne takiego typu mogą być używane w klauzuli switch Karta karta; switch karta{ case Karta.pik ... } Nie są konieczne zmiany JVM Implementowane przez kompilator Nowa klasa java.lang.Enum, po której dziedziczą wszystkie zmienne typu wyliczeniowego Deklaracja jest nowym rodzajem deklaracji klasy W szczególności, nie jest legalne jawne tworzenie instancji enumeracji przy użyciu new()
29 Typy wyliczeniowy w Java 1.5A Typesafe Enum Facility for the Javatm Programming Language Effective Java Programming: Substitutes for Missing C Constructs Typesafe Enum: Using enum in J2SE 1.5 (Tiger) Beware of Java typesafe enumerations
30 Literatura i URLs Wprowadzenie do użycia Generics The Java Language Specification, dostępna z java.sun.com