Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Wybrane elementy języka Java – ciąg dalszy Paweł Zdziarski.

Podobne prezentacje


Prezentacja na temat: "Wybrane elementy języka Java – ciąg dalszy Paweł Zdziarski."— Zapis prezentacji:

1 Wybrane elementy języka Java – ciąg dalszy Paweł Zdziarski

2 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

3 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 sparametryzowane Obecne 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 myIntList = new LinkedList (); myIntList.add(new Integer(0)); Integer x = myIntList.iterator().next();

5 Typy sparametryzowane - składnia Deklaracja: używamy formalnego parametru typu, np. public interface List { void add(E x); Iterator iterator(); } Wywołanie: typ sparametryzowany, np. List myList; intuicyjne rozumienie wywołania: każde wystąpienie formalnego parametru typu w deklaracji typu sparametryzowanego zastępujemy faktycznym parametrem typu, np. zastępujemy we wszystkich metodach List wystąpnienia E typem Integer W rzeczywistości, skompilowany kod typu sparametryzowanego istnieje tylko w jednej kopii (jeden plik klasy.class)

6 Typy sparametryzowane - wildcards Jak napisać metodę wypisującą wszystkie elementy kolekcji? void printCollection(Collection c) { for (Object e : c) { System.out.println(e);}} (używamy dodatkowo nowej postaci pętli for) –Skoro Collection nie jest nadtypem innej sparametryzowanej kolekcji, musielibyśmy stworzyć odpowiednie metody do wypisywania elementów Collection etc. Collection jest nadtypem wszystkich kolekcji. ? Jest typem wildcard void printCollection(Collection c) { for (Object e : c) { System.out.println(e);}}

7 Typy sparametryzowane – bounded wildcards Nawet jeśli Shape jest nadtypem Circle, Rectangle etc., List nie jest nadtypem List, List Możemy jawnie zadeklarować tzw. upper bound parametru typu List

8 Typy sparametryzowane – implementacja, erasure Problem używania kodu generics z kodem wcześniejszych wersji Javy public String loophole(Integer x) { List ys = new LinkedList ; List xs = ys; xs.add(x); ys.iterator().next(); } –Jak we wcześniejszym przykładzie, tworzymy alias xs do zmiennej ys typu spararametryzowanego List –Tutaj kod się kompiluje (kompilator daje jedynie ostrzeżenie), natomiast użycie błędnego typu daje błąd wykonania (ClassCastException) return (String) ys.iterator().next(); Implementacja generics działa jako przód (front-end) normalnego kompilatora Javy, kod z użyciem generics jest zamieniany na normalny bytecode Javy w trakcie procesu nazwanego erasure

9 Typy sparametryzowane – implementacja, erasure Kod sparametryzowany public String loophole(Integer x) { List ys = new LinkedList ; List xs = ys; xs.add(x); ys.iterator().next(); } zostanie przetłumaczony 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 poprawność użycia typów sparametryzowanych (np. nie moglibyśmy zadeklarować List xs) –Do wynikowego kodu zwykłej Javy dodawane są rzutowania wszędzie, gdzie może wystąpić niepoprawne (pod wzgl. typów) przypisanie

10 Typy sparametryzowane - erasure Mechanizm polega na mapowaniu typów sparametryzowanych do typów niesparametryzowanych Erasure klasy niesparametryzowanej nie zmienia definicji tej klasy Typy sparametryzowane tracą typ parametru Tree Typ parametru jest mapowany do swojego upper bound T (w klasie Tree) Object ale Bush T (w klasie Bush) Color Wstawiane są odpowiednie rzutowania

11 Typy sparametryzowane - erasure Czy skopiluje się class ShoppingCart { //... } class ShoppingCart { //... } ? Nie: po erasure, obie klasy miałyby tą samą nazwę

12 Typy sparametryzowane - erasure Czy skompiluje się class TwoForOneSpecial { public void add(T newRentable) { //... } public void add(W newRentable) { //... } } ? Nie: po erasure, obie metody mają te same sygnatury

13 Typy sparametryzowane - erasure Czy skompiluje się class GetAFreeVideoTape { public void add(T anything) { //... } public void add(W videotape) { //... } ? Tak: po erasure dostaniemy kod odpowiadający class GetAFreeVideoTape { public void add(Rentable anything) { //... } public void add(Videotape videotape) { //... }

14 Typy sparametryzowane – jeden kod klasy Dlaczego nie jest poprawna konstrukcja class MyClass { static T member; } ? Tworząc wiele instancji typu sparametryzowanego, np. MyClass myIntClass; MyClass myStringClass; mielibyśmy tylko jedną kopię member w pamięci. Jakiego typu byłaby ta zmienna?

15 Typy sparametryzowane – jeden kod klasy Jaki wynik da wykonanie List l1 = new ArrayList (); List l2 = new ArrayList (); System.out.println(l1.getClass() == l2.getClass()); ? Ponieważ kod z użyciem generics i tak jest tłumaczony do kodu bez typów sparametryzowanych, wszystkie instancje klas sparametryzowanych są tej samej klasy true

16 Typy sparametryzowane i dziedziczenie Fragment kodu List ls = new ArrayList (); List lo = ls; daje błąd kompilacji w linii 2 Intuicyjne rozumienie List jako nadtypu List nie jest poprawne! Rozważając lo.add(new Object()); String s = ls.get(0); –Wcześniej stworzyliśmy alias do obiektu lo o nazwie ls –W pierwszej linii wstawiamy do listy element typu Object – nie ma już gwarancji, że lista przechowuje elementy wyłącznie typu String –Jeśli cały kod kompilowałby się, druga linia nie zachowywałaby poprawności typów Ogólnie, mimo iż A extends B to jednak List nie jest podtypem List

17 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 types Do 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 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 kolekcji Dotychczas (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 c) { Iterator itr = c.iterator(); while (itr.hasNext()) { itr.next().draw(); }

21 Pętla foreach + generics Nowa dopuszczalna postać pętli for public void drawAll(Collection c) { for (Shape s:c) s.draw(); } Rozwijane automatycznie do kodu for (Iterator $i = c.iterator(); $i.hasNext();) { Shape s = $i.next(); s.draw(); }

22 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 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; } 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 - inlining Kompilator 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 enum Zdefiniuj 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 enum Uż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 APIs 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.5 Wbudowany 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.5 A Typesafe Enum Facility for the Java tm Programming Language Effective Java Programming: Substitutes for Missing C Constructs eenums 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.comjava.sun.com


Pobierz ppt "Wybrane elementy języka Java – ciąg dalszy Paweł Zdziarski."

Podobne prezentacje


Reklamy Google