Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00120 006624 13598266 na godz. na dobę w sumie
Java w pigułce. Wydanie VI - ebook/pdf
Java w pigułce. Wydanie VI - ebook/pdf
Autor: , Liczba stron: 352
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-283-0626-4 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> java - programowanie
Porównaj ceny (książka, ebook, audiobook).

Poznaj nowości języka Java!

Java to język programowania wybierany wszędzie tam, gdzie są wymagane najwyższe bezpieczeństwo i wydajność. Znajduje zastosowanie przy tworzeniu systemów bankowych oraz zaawansowanych aplikacji do zarządzania przedsiębiorstwami. Są to obszary, w których pomyłki bywają niezwykle drogie. Ale to nie jedyne zastosowania Javy! Ten język sprawdza się również wtedy, gdy trzeba szybko stworzyć aplikację internetową (niezależnie od jej wielkości) albo narzędzia różnego przeznaczenia. Java przyda się wszędzie!

W ostatnim czasie na rynku pojawiły się dwie kolejne wersje tego języka, oznaczone numerami 7 i 8. Zawierają one wiele nowości i ulepszeń, dzięki którym życie programisty staje się prostsze, a tworzone oprogramowanie — lepsze. Najnowsze wydanie tej cenionej książki zostało uzupełnione o informacje na temat tych właśnie wersji. Dzięki niej błyskawicznie poznasz i wykorzystasz nowe techniki w codziennej pracy. Sięgnij po ten podręcznik i poznaj najlepsze techniki programowania współbieżnego, zasady podejścia obiektowego oraz możliwości asynchronicznego wykonywania operacji wejścia-wyjścia. Ta książka jest obowiązkową lekturą dla wszystkich programistów języka Java!

Poznaj najskrytsze tajemnice języka Java!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Java in a Nutshell, 6th Edition Tłumaczenie: Łukasz Piwko ISBN: 978-83-283-0623-3 © 2015 Helion S.A. Authorized Polish translation of the English edition of Java in a Nutshell, 6th Edition, ISBN 9781449370824 © 2015 Benjamin J. Evans and David Flanagan. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/javpi6.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/javpi6 Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis tre(cid:316)ci Przedmowa ....................................................................................................................9 Wst(cid:253)p ............................................................................................................................11 Cz(cid:253)(cid:316)(cid:235) I. Wprowadzenie do j(cid:253)zyka Java .......................................................... 17 1. Wprowadzenie do (cid:316)rodowiska Java ........................................................................... 19 19 23 24 26 27 28 J(cid:246)zyk, maszyna wirtualna i (cid:264)rodowisko Historia Javy i maszyny wirtualnej Javy w zarysie Cykl istnienia programu Java Bezpiecze(cid:254)stwo Javy Porównanie Javy z innymi j(cid:246)zykami programowania Krytyka Javy 2. Sk(cid:293)adnia Javy od podstaw ........................................................................................... 31 32 32 35 42 55 71 77 81 87 91 95 96 97 Budowa programu w Javie Struktura leksykalna Podstawowe typy danych Wyra(cid:276)enia i operatory Instrukcje Metody Podstawowe wiadomo(cid:264)ci o klasach i obiektach Tablice Typy referencyjne Pakiety i przestrzenie nazw Struktura plików Javy Definiowanie i uruchamianie programów Java Podsumowanie 5 Kup książkęPoleć książkę 3. Programowanie obiektowe w Javie ...........................................................................99 99 101 107 111 119 125 129 Podstawowe wiadomo(cid:264)ci o klasach Pola i metody Tworzenie i inicjowanie obiektów Podklasy i dziedziczenie Ukrywanie danych i hermetyzacja Klasy i metody abstrakcyjne Podsumowanie wiadomo(cid:264)ci o modyfikatorach 4. System typów Javy .....................................................................................................131 131 137 145 148 162 165 Interfejsy Typy ogólne Wyliczenia i adnotacje Typy zagnie(cid:276)d(cid:276)one Wyra(cid:276)enia lambda Podsumowanie 5. Podstawy projektowania obiektowego w Javie .......................................................167 167 168 172 180 182 Warto(cid:264)ci w j(cid:246)zyku Java Wa(cid:276)ne metody klasy java.lang.Object Aspekty projektowania obiektowego Wyj(cid:241)tki i ich obs(cid:228)uga Bezpieczne programowanie w Javie 6. Zarz(cid:233)dzanie pami(cid:253)ci(cid:233) i wspó(cid:293)bie(cid:348)no(cid:316)(cid:235) w Javie ....................................................... 185 185 188 191 193 195 203 205 Podstawowe poj(cid:246)cia zarz(cid:241)dzania pami(cid:246)ci(cid:241) w Javie Optymalizacja procesu usuwania nieu(cid:276)ywanych obiektów w maszynie wirtualnej Sterta maszyny wirtualnej HotSpot Finalizacja Mechanizmy wspó(cid:228)bie(cid:276)no(cid:264)ci w Javie Praca z w(cid:241)tkami Podsumowanie Cz(cid:253)(cid:316)(cid:235) II. Praca na platformie Java ................................................................ 207 7. Zwyczaje programistyczne i tworzenie dokumentacji ............................................209 209 211 212 219 Konwencje nazewnicze i dotycz(cid:241)ce stosowania wielkich liter Nadawanie nazw w praktyce Komentarze dokumentacyjne Porady na temat pisania programów przeno(cid:264)nych 6 (cid:95) Spis tre(cid:316)ci Kup książkęPoleć książkę 8. Praca z kolekcjami i tablicami w Javie ......................................................................223 223 239 245 Wprowadzenie do API Collections Wyra(cid:276)enia lambda w kolekcjach Javy Podsumowanie 9. Obs(cid:293)uga najcz(cid:253)(cid:316)ciej u(cid:348)ywanych formatów danych .................................................247 247 253 258 263 Tekst Liczby i matematyka Data i godzina w Javie 8 Podsumowanie 10. Obs(cid:293)uga plików oraz wej(cid:316)cia i wyj(cid:316)cia .....................................................................265 265 270 273 275 278 Klasyczny system wej(cid:264)cia i wyj(cid:264)cia Javy Nowy system wej(cid:264)cia i wyj(cid:264)cia Kana(cid:228)y i bufory NIO Asynchroniczny system wej(cid:264)cia i wyj(cid:264)cia Sie(cid:232) 11. (cid:292)adowanie klas, refleksja oraz uchwyty do metod ..................................................283 283 285 287 289 292 295 297 Pliki klas, obiekty klas i metadane Fazy (cid:228)adowania klasy Bezpieczne programowanie i (cid:228)adowanie klas (cid:227)adowanie klas w praktyce Refleksja Dynamiczne klasy po(cid:264)rednicz(cid:241)ce Uchwyty do metod 12. Nashorn ...................................................................................................................... 301 301 302 308 310 315 Wprowadzenie do Nashorna Wykonywanie kodu JavaScript w Nashornie Nashorn i pakiet javax.script Nashorn dla zaawansowanych Podsumowanie 13. Narz(cid:253)dzia platformy i profile .....................................................................................317 317 329 334 339 Narz(cid:246)dzia wiersza polece(cid:254) Narz(cid:246)dzie VisualVM Profile Java 8 Podsumowanie Skorowidz .................................................................................................................. 341 Spis tre(cid:316)ci (cid:95) 7 Kup książkęPoleć książkę 8 (cid:95) Spis tre(cid:316)ci Kup książkęPoleć książkę ROZDZIA(cid:292) 4. System typów Javy W tym rozdziale przechodzimy od podstaw programowania obiektowego przy u(cid:276)yciu klas do dalszych poj(cid:246)(cid:232), których znajomo(cid:264)(cid:232) równie(cid:276) jest potrzebna ka(cid:276)demu, kto chce efektywnie wykorzystywa(cid:232) statyczny system typów j(cid:246)zyka Java. J(cid:246)zyk programowania o statycznej kontroli typów to taki, w którym zmienne maj(cid:241) okre(cid:264)lone typy i przypisanie warto(cid:264)ci do zmiennej nieodpowiedniego typu powo- duje b(cid:228)(cid:241)d kompilacji. Przyk(cid:228)adem takiego j(cid:246)zyka jest Java. J(cid:246)zyki, w których zgod- no(cid:264)(cid:232) typów jest sprawdzana dopiero w czasie dzia(cid:228)ania programu, nazywaj(cid:241) si(cid:246) j(cid:246)- zykami o dynamicznej kontroli typów. Przyk(cid:228)adem takiego j(cid:246)zyka jest JavaScript. System typów Javy sk(cid:228)ada si(cid:246) nie tylko z klas i typów podstawowych, ale równie(cid:276) z innych rodzajów typów referencyjnych, które s(cid:241) zwi(cid:241)zane z podstawow(cid:241) koncepcj(cid:241) klas, tylko ró(cid:276)- ni(cid:241) si(cid:246) od nich pod ró(cid:276)nymi wzgl(cid:246)dami i zazwyczaj s(cid:241) traktowane przez kompilator javac lub maszyn(cid:246) wirtualn(cid:241) w specjalny sposób. W poprzednich rozdzia(cid:228)ach opisali(cid:264)my ju(cid:276) tablice i klasy, czyli dwa najcz(cid:246)(cid:264)ciej u(cid:276)ywane rodzaje typów referencyjnych j(cid:246)zyka Java. W tym rozdziale zaczynamy opis kolejnego wa(cid:276)nego typu referencyjnego — interfejsów. Potem przejdziemy do typów ogólnych (generycznych), które równie(cid:276) pe(cid:228)ni(cid:241) bardzo wa(cid:276)n(cid:241) funkcj(cid:246) w systemie typów Javy. Uzbrojeni w t(cid:246) wiedz(cid:246) przej- dziemy do ró(cid:276)nic mi(cid:246)dzy typami czasu kompilacji i czasu wykonywania programu. Aby dope(cid:228)ni(cid:232) obrazu typów referencyjnych j(cid:246)zyka Java, przyjrzymy si(cid:246) te(cid:276) dwóm specjalnym rodzajom klas i interfejsów — wyliczeniom i adnotacjom. Na ko(cid:254)cu rozdzia(cid:228)u dowiesz si(cid:246), czym s(cid:241) typy zagnie(cid:276)d(cid:276)one, i poznasz wprowadzone w Javie 8 wyra(cid:276)enia lambda. Zaczniemy od interfejsów, które s(cid:241) chyba najwa(cid:276)niejszym po klasach typem referencyjnym w Javie i stanowi(cid:241) kluczowy sk(cid:228)adnik budowy ca(cid:228)ego systemu typów tego j(cid:246)zyka. Interfejsy W rozdziale 3. opisali(cid:264)my poj(cid:246)cie dziedziczenia. Napisali(cid:264)my te(cid:276), (cid:276)e w Javie ka(cid:276)da klasa mo(cid:276)e dziedziczy(cid:232) bezpo(cid:264)rednio tylko po jednej klasie. Jest to do(cid:264)(cid:232) powa(cid:276)ne ograniczenie dla rodzajów programów obiektowych, jakie mo(cid:276)na pisa(cid:232). Projektanci Javy zdawali sobie z tego spraw(cid:246), ale chcieli, aby mechanizmy obiektowo(cid:264)ci w ich j(cid:246)zyku by(cid:228)y prostsze ni(cid:276) np. w j(cid:246)zyku C++. 131 Kup książkęPoleć książkę Postanowili wi(cid:246)c zastosowa(cid:232) inne rozwi(cid:241)zanie — o nazwie interfejs. Interfejs podobnie jak klasa stanowi definicj(cid:246) nowego typu referencyjnego. Zgodnie z nazw(cid:241) reprezentuje on tylko interfejs API — a wi(cid:246)c dostarcza opisu typu i metod (oraz sygnatury), które klasy implemen- tuj(cid:241)ce go powinny definiowa(cid:232). Ogólnie rzecz bior(cid:241)c, interfejs w Javie nie dostarcza (cid:276)adnego kodu implementacyjnego dla opisywanych przez siebie metod. Ich implementacja jest obowi(cid:241)zkowa dla ka(cid:276)dej klasy, któ- ra implementuje dany interfejs. Ale interfejs mo(cid:276)e te(cid:276) zawiera(cid:232) metody oznaczone jako opcjonalne, które nie musz(cid:241) zosta(cid:232) zdefiniowane w klasie implementuj(cid:241)cej ten interfejs. Do oznaczania takich metod s(cid:228)u(cid:276)y s(cid:228)owo kluczowe default. Metody oznaczone tym modyfikatorem musz(cid:241) mie(cid:232) w interfejsie domy(cid:264)ln(cid:241) definicj(cid:246), która b(cid:246)dzie u(cid:276)ywana we wszystkich implementacjach, w których nie zostan(cid:241) zdefi- niowane. Mo(cid:276)liwo(cid:264)(cid:232) tworzenia metod opcjonalnych w interfejsach jest nowo(cid:264)ci(cid:241) wprowadzon(cid:241) w Javie 8. Szerzej na temat metod opcjonalnych interfejsów piszemy w podrozdziale „Metody domy(cid:264)lne”. Nie da si(cid:246) bezpo(cid:264)rednio utworzy(cid:232) obiektu interfejsu ani sk(cid:228)adowej typu interfejsowego. Zamiast tego nale(cid:276)y utworzy(cid:232) klas(cid:246) implementuj(cid:241)c(cid:241) dany interfejs i w niej zdefiniowa(cid:232) niezb(cid:246)dne metody. Wszystkie egzemplarze takiej klasy s(cid:241) obiektami zarówno typu zdefiniowanego przez t(cid:246) klas(cid:246), jak i typu zdefiniowanego przez interfejs. Obiekty nienale(cid:276)(cid:241)ce do tej samej klasy lub nadklasy i tak mog(cid:241) by(cid:232) tego samego typu dzi(cid:246)ki implementacji tego samego interfejsu. Definiowanie interfejsu Definicja interfejsu wygl(cid:241)da bardzo podobnie do definicji klasy, w której wszystkie (nieb(cid:246)d(cid:241)ce domy(cid:264)lnymi) metody s(cid:241) abstrakcyjne, a s(cid:228)owo kluczowe class zast(cid:241)piono s(cid:228)owem interface. Na przyk(cid:228)ad poni(cid:276)ej znajduje si(cid:246) definicja interfejsu o nazwie Centered. Klasa Shape, np. taka jak przedstawiona w przyk(cid:228)adach w rozdziale 3., mo(cid:276)e implementowa(cid:232) ten interfejs, je(cid:264)li progra- mista chce umo(cid:276)liwi(cid:232) ustawianie i sprawdzanie wspó(cid:228)rz(cid:246)dnych (cid:264)rodka: interface Centered { void setCenter(double x, double y); double getCenterX(); double getCenterY(); } Sk(cid:228)adowe interfejsu podlegaj(cid:241) pewnym ograniczeniom: (cid:120) Wszystkie obowi(cid:241)zkowe metody interfejsu standardowo s(cid:241) abstrakcyjne i zamiast tre(cid:264)ci musz(cid:241) mie(cid:232) tylko (cid:264)rednik. Mo(cid:276)na stosowa(cid:232) modyfikator abstract, ale zwyczajowo si(cid:246) go opuszcza. (cid:120) Interfejs definiuje publiczny interfejs API. Wszystkie sk(cid:228)adowe s(cid:241) wi(cid:246)c publiczne i zwy- czajowo opuszcza si(cid:246) modyfikator public. Definicja metody chronionej lub prywatnej w interfejsie jest b(cid:228)(cid:246)dem, który zostanie wychwycony w czasie kompilacji. 132 (cid:95) Rozdzia(cid:293) 4. System typów Javy Kup książkęPoleć książkę (cid:120) Interfejs nie mo(cid:276)e zawiera(cid:232) definicji pól egzemplarzowych. Pola s(cid:241) szczegó(cid:228)em imple- mentacyjnym, a interfejs jest specyfikacj(cid:241), nie implementacj(cid:241). W interfejsach dopuszczal- ne s(cid:241) jedynie sta(cid:228)e, zarazem statyczne, jak i finalne. (cid:120) Nie mo(cid:276)na tworzy(cid:232) egzemplarzy interfejsów, wi(cid:246)c interfejs nie mo(cid:276)e zawiera(cid:232) konstruktora. (cid:120) Interfejsy mog(cid:241) zawiera(cid:232) typy zagnie(cid:276)d(cid:276)one, które domy(cid:264)lnie s(cid:241) statyczne i publiczne. Szczegó(cid:228)owy opis typów zagnie(cid:276)d(cid:276)onych znajduje si(cid:246) w podrozdziale „Typy zagnie(cid:276)d(cid:276)one”. (cid:120) Od Javy 8 interfejs mo(cid:276)e zawiera(cid:232) metody statyczne. W poprzednich wersjach j(cid:246)zyka by(cid:228)o to niedozwolone i powszechnie uwa(cid:276)ano to za wad(cid:246) projektow(cid:241) tego j(cid:246)zyka programowania. Rozszerzanie interfejsów Interfejs mo(cid:276)e rozszerza(cid:232) inny interfejs i podobnie jak klasa mo(cid:276)e w definicji zawiera(cid:232) klau- zul(cid:246) extends. Gdy jeden interfejs rozszerza inny, dziedziczy po nim wszystkie metody i sta(cid:228)e oraz mo(cid:276)e zawiera(cid:232) dodatkowe w(cid:228)asne metody i sta(cid:228)e. Ale w odró(cid:276)nieniu od klas klauzula extends interfejsu mo(cid:276)e zawiera(cid:232) wi(cid:246)cej ni(cid:276) jedn(cid:241) nazw(cid:246) nadinterfejsu. Poni(cid:276)ej znajduje si(cid:246) kilka przyk(cid:228)adów interfejsów rozszerzaj(cid:241)cych inne interfejsy: interface Positionable extends Centered { void setUpperRightCorner(double x, double y); double getUpperRightX(); double getUpperRightY(); } interface Transformable extends Scalable, Translatable, Rotatable {} interface SuperShape extends Positionable, Transformable {} Interfejs rozszerzaj(cid:241)cy kilka interfejsów dziedziczy wszystkie metody i sta(cid:228)e ka(cid:276)dego z nich oraz mo(cid:276)e dodatkowo zawiera(cid:232) w(cid:228)asne metody i sta(cid:228)e. Klasa implementuj(cid:241)ca taki interfejs musi implementowa(cid:232) metody abstrakcyjne zdefiniowane bezpo(cid:264)rednio przez ten interfejs i wszystkie odziedziczone ze wszystkich nadinterfejsów. Implementowanie interfejsu Podobnie jak za pomoc(cid:241) s(cid:228)owa kluczowego extends oznacza si(cid:246) nadklas(cid:246) klasy, za pomoc(cid:241) s(cid:228)owa kluczowego implements oznacza si(cid:246) interfejsy, które ona implementuje. S(cid:228)owo kluczowe implements mo(cid:276)e si(cid:246) znajdowa(cid:232) w definicji klasy za klauzul(cid:241) extends. Po nim wypisuje si(cid:246) rozdzielan(cid:241) przecinkami list(cid:246) implementowanych przez klas(cid:246) interfejsów. Deklaracja interfejsu w klauzuli implements klasy oznacza, (cid:276)e dana klasa implementuje (tzn. zawiera tre(cid:264)(cid:232) g(cid:228)ówn(cid:241) definicji) ka(cid:276)d(cid:241) obowi(cid:241)zkow(cid:241) metod(cid:246) tego interfejsu. Je(cid:276)eli klasa im- plementuje interfejs, ale nie dostarcza implementacji wszystkich jego obowi(cid:241)zkowych metod, to dziedziczy te metody abstrakcyjne i sama musi by(cid:232) zadeklarowana jako abstrakcyjna. Je(cid:264)li klasa implementuje wi(cid:246)cej ni(cid:276) jeden interfejs, musi implementowa(cid:232) wszystkie obowi(cid:241)zkowe metody ka(cid:276)dego z tych interfejsów (albo by(cid:232) zadeklarowana jako abstrakcyjna). Poni(cid:276)ej znajduje si(cid:246) definicja klasy CenteredRectangle, która rozszerza klas(cid:246) Rectangle z roz- dzia(cid:228)u 3. i implementuje interfejs Centered: public class CenteredRectangle extends Rectangle implements Centered { // nowe pola egzemplarzowe private double cx, cy; // konstruktor Interfejsy (cid:95) 133 Kup książkęPoleć książkę public CenteredRectangle(double cx, double cy, double w, double h) { super(w, h); this.cx = cx; this.cy = cy; } // Klasa dziedziczy wszystkie metody klasy Rectangle, ale musi zawiera(cid:252) implementacje wszystkich metod interfejsu Centered. public void setCenter(double x, double y) { cx = x; cy = y; } public double getCenterX() { return cx; } public double getCenterY() { return cy; } } Za(cid:228)ó(cid:276)my, (cid:276)e w podobny sposób zaimplementowali(cid:264)my te(cid:276) klasy CenteredCircle i CenteredSqu- are. Ka(cid:276)da z nich rozszerza klas(cid:246) Shape, wi(cid:246)c egzemplarze tych klas mo(cid:276)na traktowa(cid:232) jak eg- zemplarze klasy Shape. Jako (cid:276)e ka(cid:276)da z nich implementuje interfejs Centered, to ich egzemplarze mo(cid:276)na te(cid:276) traktowa(cid:232) jako obiekty tego typu. W poni(cid:276)szym przyk(cid:228)adzie pokazano, (cid:276)e obiekty mog(cid:241) by(cid:232) jednocze(cid:264)nie typu klasowego i interfejsowego: Shape[] shapes = new Shape[3]; // tworzy tablic(cid:266) do przechowywania kszta(cid:225)tów // tworzy kilka wycentrowanych kszta(cid:225)tów i zapisuje je w tablicy Shape[] // Nie trzeba stosowa(cid:252) rzutowania: wszystko to s(cid:261) konwersje rozszerzaj(cid:261)ce. shapes[0] = new CenteredCircle(1.0, 1.0, 1.0); shapes[1] = new CenteredSquare(2.5, 2, 3); shapes[2] = new CenteredRectangle(2.3, 4.5, 3, 4); // oblicza (cid:286)rednie pole powierzchni kszta(cid:225)tów i // (cid:286)redni(cid:261) odleg(cid:225)o(cid:286)(cid:252) od pocz(cid:261)tku uk(cid:225)adu wspó(cid:225)rz(cid:266)dnych double totalArea = 0; double totalDistance = 0; for( int i = 0; i shapes.length; i++) { totalArea += shapes[i].area(); // oblicza pole powierzchni kszta(cid:225)tów // Uwaga: zasadniczo u(cid:298)ycie operatora instanceof w celu sprawdzenia // typu czasu wykonywania obiektu cz(cid:266)sto jest oznak(cid:261) problemów projektowych programu. if (shapes[i] instanceof Centered) { // Kszta(cid:225)t jest typu Centered. // Zwró(cid:252) uwag(cid:266) na rzutowanie z typu Shape na Centered (nie by(cid:225)oby potrzebne // do konwersji z typu CenteredSquare na Centered). Centered c = (Centered) shapes[i]; double cx = c.getCenterX(); // pobranie wspó(cid:225)rz(cid:266)dnych (cid:286)rodka double cy = c.getCenterY(); // obliczenie odleg(cid:225)o(cid:286)ci od pocz(cid:261)tku uk(cid:225)adu totalDistance += Math.sqrt(cx*cx + cy*cy); } } System.out.println( (cid:165)rednie pole powierzchni: + totalArea/shapes.length); System.out.println( (cid:165)rednia odleg(cid:239)o(cid:258)(cid:202): + totalDistance/shapes.length); W Javie interfejsy, podobnie jak klasy, s(cid:241) typami danych. Gdy klasa implementuje inter- fejs, to egzemplarze tej klasy mo(cid:276)na przypisywa(cid:232) do zmiennych typu tego interfejsu. Nie nale(cid:276)y interpretowa(cid:232) tego przyk(cid:228)adu w ten sposób, (cid:276)e konieczne jest przypisanie obiektu ty- pu CenteredRectangle do zmiennej typu Centered przed wywo(cid:228)aniem metody setCenter() ani do zmiennej typu Shape przed wywo(cid:228)aniem metody area(). Klasa CenteredRectangle zawiera defi- nicje tych metod odziedziczone po nadklasie Rectangle, wi(cid:246)c mo(cid:276)na je wywo(cid:228)ywa(cid:232) w dowol- nym momencie. 134 (cid:95) Rozdzia(cid:293) 4. System typów Javy Kup książkęPoleć książkę Implementowanie kilku interfejsów Za(cid:228)ó(cid:276)my, (cid:276)e potrzebne s(cid:241) obiekty kszta(cid:228)tów, które mo(cid:276)na pozycjonowa(cid:232) nie tylko wzgl(cid:246)dem punktu (cid:264)rodkowego, ale i prawego górnego rogu. Dodatkowo powiedzmy, (cid:276)e potrzebna jest mo(cid:276)liwo(cid:264)(cid:232) zmniejszania i zwi(cid:246)kszania tych kszta(cid:228)tów. Przypomnijmy, (cid:276)e wprawdzie klasa mo(cid:276)e bezpo(cid:264)rednio dziedziczy(cid:232) tylko po jednej klasie, ale mo(cid:276)e implementowa(cid:232) dowoln(cid:241) licz- b(cid:246) interfejsów. Przy za(cid:228)o(cid:276)eniu, (cid:276)e istniej(cid:241) odpowiednie interfejsy UpperRightCornered i Scalable, klas(cid:246) o (cid:276)(cid:241)danych w(cid:228)a(cid:264)ciwo(cid:264)ciach mo(cid:276)na zadeklarowa(cid:232) w nast(cid:246)puj(cid:241)cy sposób: public class SuperDuperSquare extends Shape implements Centered, UpperRightCornered, Scalable { // Sk(cid:225)adowe klasy zosta(cid:225)y pomini(cid:266)te. } Implementacja kilku interfejsów przez klas(cid:246) oznacza tylko tyle, (cid:276)e klasa ta musi zawiera(cid:232) imple- mentacje wszystkich abstrakcyjnych (obowi(cid:241)zkowych) metod ze wszystkich tych interfejsów. Metody domy(cid:316)lne W j(cid:246)zyku Java 8 pojawi(cid:228)a si(cid:246) mo(cid:276)liwo(cid:264)(cid:232) definiowania w interfejsach metod zawieraj(cid:241)cych implementacj(cid:246). S(cid:241) to metody opcjonalne w reprezentowanym przez interfejs API i najcz(cid:246)(cid:264)ciej nazywa si(cid:246) je metodami domy(cid:264)lnymi. Ich poznawanie zaczniemy od przeanalizowania po- wodów, dla których s(cid:241) one w ogóle potrzebne. Zgodno(cid:316)(cid:235) wsteczna Twórcy platformy Java od zawsze du(cid:276)o uwagi po(cid:264)wi(cid:246)caj(cid:241) kwestiom zgodno(cid:264)ci nowych wer- sji ze starszymi. To sprawia, (cid:276)e kod napisany (a nawet skompilowany) dla starszej wersji platformy musi dzia(cid:228)a(cid:232) na nowszych wersjach. Zasada ta daje programistom pewno(cid:264)(cid:232), (cid:276)e nowe wydanie pakietu JDK lub (cid:264)rodowiska JRE nie spowoduje, i(cid:276) aktualnie dzia(cid:228)aj(cid:241)cy program nagle przestanie dzia(cid:228)a(cid:232). Zgodno(cid:264)(cid:232) wsteczna jest wielk(cid:241) zalet(cid:241) platformy Java, ale jej utrzymanie wi(cid:241)(cid:276)e si(cid:246) z pewnymi niedogodno(cid:264)ciami. Jedn(cid:241) z nich jest to, (cid:276)e do interfejsów nie mo(cid:276)na dodawa(cid:232) nowych obo- wi(cid:241)zkowych metod. Powiedzmy np., (cid:276)e chcemy wzbogaci(cid:232) interfejs Positionable o mo(cid:276)liwo(cid:264)(cid:232) okre(cid:264)lania tak(cid:276)e pozycji lewego dolnego rogu: public interface Positionable extends Centered { void setUpperRightCorner(double x, double y); double getUpperRightX(); double getUpperRightY(); void setLowerLeftCorner(double x, double y); double getLowerLeftX(); double getLowerLeftY(); } Je(cid:264)li po wprowadzeniu tych zmian spróbujemy u(cid:276)y(cid:232) tego interfejsu z wcze(cid:264)niej napisanym kodem, to kod ten nie zadzia(cid:228)a, poniewa(cid:276) b(cid:246)dzie w nim brakowa(cid:228)o obowi(cid:241)zkowych metod setLowerLeftCorner(), getLowerLeftX() i getLowerLeftY(). Interfejsy (cid:95) 135 Kup książkęPoleć książkę Opisywany problem mo(cid:276)na (cid:228)atwo zaobserwowa(cid:232) we w(cid:228)asnym kodzie. Wystarczy skom- pilowa(cid:232) plik klasy implementuj(cid:241)cej interfejs, a potem doda(cid:232) do tego interfejsu now(cid:241) obowi(cid:241)zkow(cid:241) metod(cid:246) i spróbowa(cid:232) uruchomi(cid:232) program z t(cid:241) now(cid:241) wersj(cid:241) interfejsu i sta- rym plikiem klasy. Powinna nast(cid:241)pi(cid:232) awaria programu z b(cid:228)(cid:246)dem NoClassDefError. Ograniczenie to stanowi(cid:228)o problem dla projektantów Javy 8, poniewa(cid:276) jednym z ich celów by(cid:228)o uaktualnienie rdzennych bibliotek kolekcji i wprowadzenie metod u(cid:276)ywaj(cid:241)cych wyra(cid:276)e(cid:254) lambda. Rozwi(cid:241)zanie wymaga(cid:228)o wprowadzenia nowego mechanizmu umo(cid:276)liwiaj(cid:241)cego modyfikowa- nie interfejsów o dodatek nowych opcjonalnych metod bez uniemo(cid:276)liwiania dzia(cid:228)ania starym programom. Implementacja metod domy(cid:316)lnych Aby doda(cid:232) nowe metody do interfejsu i nie spowodowa(cid:232) niezgodno(cid:264)ci ze starszymi progra- mami, konieczne by(cid:228)o dostarczenie implementacji tych metod, która pozwoli(cid:228)aby tym pro- gramom dzia(cid:228)a(cid:232) tak jak dotychczas. Zastosowano rozwi(cid:241)zanie w postaci metod domy(cid:264)lnych, które wprowadzono w Javie 8. Metod(cid:246) domy(cid:264)ln(cid:241) (czasami nazywan(cid:241) metod(cid:241) opcjonaln(cid:241)) mo(cid:276)na doda(cid:232) do ka(cid:276)dego interfejsu. Musi ona zawiera(cid:232) tzw. implementacj(cid:246) domy(cid:264)ln(cid:241), któr(cid:241) wpisuje si(cid:246) bez- po(cid:264)rednio w definicji interfejsu. Podstawowe cechy metod domy(cid:264)lnych s(cid:241) nast(cid:246)puj(cid:241)ce: (cid:120) Klasa implementuj(cid:241)ca mo(cid:276)e implementowa(cid:232) metod(cid:246) domy(cid:264)ln(cid:241), ale nie musi tego robi(cid:232). (cid:120) Je(cid:276)eli klasa implementuje metod(cid:246) domy(cid:264)ln(cid:241), to u(cid:276)ywana jest implementacja z tej klasy. (cid:120) Je(cid:264)li nie zostanie znaleziona inna implementacja metody, stosowana jest implementacja domy(cid:264)lna. Przyk(cid:228)adem metody domy(cid:264)lnej jest metoda sort(). Zosta(cid:228)a ona dodana do interfejsu java.util.List w JDK 8, a jej definicja wygl(cid:241)da tak: // Napis E to sposób zapisu typów ogólnych w Javie — szerzej na ich // temat piszemy w nast(cid:266)pnym podrozdziale. Je(cid:286)li nie wiesz, czym s(cid:261) typy ogólne, // na razie zignoruj ten szczegó(cid:225). interface List E { // pozosta(cid:225)e sk(cid:225)adowe pomini(cid:266)to public default void sort(Comparator ? super E c) { Collections. E sort(this, c); } } W efekcie od Javy 8 ka(cid:276)dy obiekt implementuj(cid:241)cy interfejs List ma metod(cid:246) egzemplarzow(cid:241) sort(), za pomoc(cid:241) której mo(cid:276)na posortowa(cid:232) list(cid:246) przy u(cid:276)yciu odpowiedniego komparatora. Jako (cid:276)e typ zwrotny to void, mo(cid:276)na podejrzewa(cid:232), i(cid:276) metoda ta wykonuje sortowanie na miej- scu, i jest to s(cid:228)uszne podejrzenie. 136 (cid:95) Rozdzia(cid:293) 4. System typów Javy Kup książkęPoleć książkę Interfejsy znacznikowe Czasami potrzebny jest kompletnie pusty interfejs. Jego implementacja przez klas(cid:246) polega tylko na wymienieniu jego nazwy w klauzuli implements, bez konieczno(cid:264)ci pisania definicji ja- kichkolwiek metod. Sprawia to, (cid:276)e egzemplarze tej klasy automatycznie staj(cid:241) si(cid:246) te(cid:276) egzempla- rzami tego interfejsu. W Javie mo(cid:276)na sprawdzi(cid:232), czy dany obiekt jest egzemplarzem wybranego interfejsu, za pomoc(cid:241) operatora instanceof, wi(cid:246)c technika ta pozwala na dostarczenie pewnych dodatkowych informacji o obiekcie. Przyk(cid:228)adem interfejsu znacznikowego jest java.io.Serializable. Implementuje si(cid:246) go w klasie po to, by poinformowa(cid:232) strumie(cid:254) ObjectOutputStream, (cid:276)e egzemplarze tej klasy mo(cid:276)na bez- piecznie serializowa(cid:232). Innym przyk(cid:228)adem jest interfejs java.util.RandomAccess. Implementuj(cid:241) go niektóre implementacje interfejsu java.util.List, aby informowa(cid:232), (cid:276)e daj(cid:241) szybki dost(cid:246)p swobodny do elementów listy. Na przyk(cid:228)ad klasa ArrayList implementuje interfejs RandomAccess, a klasa LinkedList nie. W algorytmach, w których wa(cid:276)na jest szybko(cid:264)(cid:232) operacji dost(cid:246)pu swo- bodnego, mo(cid:276)na sprawdza(cid:232) implementacj(cid:246) interfejsu RandomAccess w nast(cid:246)puj(cid:241)cy sposób: // Przed posortowaniem elementów dowolnie d(cid:225)ugiej tablicy warto // sprawdzi(cid:252), czy umo(cid:298)liwia ona szybki swobodny dost(cid:266)p do elementów. // Je(cid:286)li nie, to szybszym rozwi(cid:261)zaniem mo(cid:298)e by(cid:252) wykonanie kopii z szybkim // dost(cid:266)pem losowym i potem wykonanie sortowania. Nie jest to jednak konieczne, // gdy u(cid:298)ywa si(cid:266) metody java.util.Collections.sort(). List l = ...; // jaka(cid:286) lista if (l.size() 2 !(l instanceof RandomAccess)) l = new ArrayList(l); sortListInPlace(l); Jak poka(cid:276)emy pó(cid:274)niej, system typów Javy jest bardzo (cid:264)ci(cid:264)le powi(cid:241)zany z nazwami typów — rozwi(cid:241)zanie to nazywa si(cid:246) typowaniem nominalnym (ang. nominal typing). Dobrym przy- k(cid:228)adem tego jest interfejs znacznikowy, który nie ma nic oprócz nazwy. Typy ogólne Jedn(cid:241) z wielkich zalet platformy Java jest jej biblioteka standardowa. Zawiera ona wiele bar- dzo przydatnych elementów, a w szczególno(cid:264)ci solidne implementacje cz(cid:246)sto u(cid:276)ywanych struktur danych. Ich obs(cid:228)uga jest w miar(cid:246) (cid:228)atwa, a poza tym istnieje dobra dokumentacja. Biblio- teki te nazywaj(cid:241) si(cid:246) kolekcjami Javy (ang. Java Collections) i po(cid:264)wi(cid:246)cili(cid:264)my im du(cid:276)(cid:241) cz(cid:246)(cid:264)(cid:232) roz- dzia(cid:228)u 8. Je(cid:264)li jednak kto(cid:264) potrzebuje znacznie obszerniejszego materia(cid:228)u, to mo(cid:276)e zaopatrzy(cid:232) si(cid:246) w ksi(cid:241)(cid:276)k(cid:246) Java Generics and Collections Maurice’a Naftalina i Philipa Wadlera (O’Reilly). Wprawdzie wczesne wersje kolekcji te(cid:276) by(cid:228)y przydatne, ale mia(cid:228)y pewn(cid:241) powa(cid:276)n(cid:241) wad(cid:246). Polega(cid:228)a ona na tym, (cid:276)e struktura danych (cz(cid:246)sto nazywana kontenerem) w istocie ukrywa(cid:228)a typ przechowywanych w niej danych. Ukrywanie i hermetyzacja to fundamenty programowania obiektowego, ale w tym przypadku nieprzezroczysto(cid:264)(cid:232) kontenera sprawia(cid:228)a programistom wiele problemów. Zaczniemy od na(cid:264)wietlenia tego problemu i poka(cid:276)emy, jak wprowadzenie typów ogólnych pozwoli(cid:228)o go rozwi(cid:241)za(cid:232) i u(cid:228)atwi(cid:232) prac(cid:246) rzeszom programistów Javy. Typy ogólne (cid:95) 137 Kup książkęPoleć książkę Wprowadzenie do typów ogólnych Je(cid:264)li kto(cid:264) chce utworzy(cid:232) kolekcj(cid:246) egzemplarzy klasy Shape, to do ich przechowywania mo(cid:276)e u(cid:276)y(cid:232) struktury danych List: List shapes = new ArrayList(); // utworzenie listy do przechowywania kszta(cid:225)tów // utworzenie paru wycentrowanych kszta(cid:225)tów i zapisanie ich w li(cid:286)cie shapes. add( new CenteredCircle(1.0, 1.0, 1.0)); // Taki kod jest dozwolony, ale stanowi bardzo z(cid:225)y wybór. shapes. add( new CenteredSquare(2.5, 2, 3)); // List::get() zwraca obiekt typu Object, wi(cid:266)c aby otrzyma(cid:252) // obiekt typu CenteredCircle, nale(cid:298)y zastosowa(cid:252) rzutowanie. CenteredCircle c = (CentredCircle)shapes. get(0); // Poni(cid:298)szy wiersz spowoduje b(cid:225)(cid:261)d wykonywania programu. CenteredCircle c = (CentredCircle)shapes. get(1); Problem w tym kodzie dotyczy konieczno(cid:264)ci przeprowadzenia rzutowania, aby otrzyma(cid:232) obiekt w nadaj(cid:241)cej si(cid:246) do u(cid:276)ytku postaci — struktura List „nie wie”, jakiego typu obiekty zawiera. Po- nadto mo(cid:276)liwe jest zapisanie w jednym kontenerze obiektów ró(cid:276)nych typów i wszystko b(cid:246)dzie w porz(cid:241)dku, dopóki kto(cid:264) nie wykona niedozwolonego rzutowania, które spowoduje awari(cid:246) programu. Potrzebna jest taka wersja listy, która rozpoznaje przechowywane w niej typy obiektów. Wówczas kompilator javac móg(cid:228)by wykrywa(cid:232) niepoprawne argumenty przekazywane do metod listy i powodowa(cid:232) b(cid:228)(cid:241)d kompilacji, zamiast odk(cid:228)ada(cid:232) t(cid:246) nieuchronn(cid:241) katastrof(cid:246) do czasu wykonywania programu. W Javie istnieje sk(cid:228)adnia pozwalaj(cid:241)ca rozwi(cid:241)za(cid:232) ten problem. Aby zaznaczy(cid:232), (cid:276)e dany typ jest kontenerem przechowuj(cid:241)cym egzemplarze pewnego typu referencyjnego, nale(cid:276)y umie(cid:264)ci(cid:232) nazw(cid:246) typu (cid:228)adunku tego kontenera w nawiasie trójk(cid:241)tnym: // utworzenie listy obiektów typu CenteredCircle List CenteredCircle shapes = new ArrayList CenteredCircle (); // utworzenie paru wycentrowanych kszta(cid:225)tów i zapisanie ich w li(cid:286)cie shapes. add( new CenteredCircle(1.0, 1.0, 1.0)); // Poni(cid:298)szy wiersz spowoduje b(cid:225)(cid:261)d kompilacji. shapes. add( new CenteredSquare(2.5, 2, 3)); // List CenteredCircle ::get() zwraca obiekt typu CenteredCircle, wi(cid:266)c nie trzeba rzutowania. CenteredCircle c = shapes. get(0); Dzi(cid:246)ki tej sk(cid:228)adni mo(cid:276)liwe jest przechwytywanie ju(cid:276) na etapie kompilacji du(cid:276)ej grupy b(cid:228)(cid:246)dów. Taki te(cid:276) jest oczywi(cid:264)cie cel tworzenia statycznego systemu typów — eliminowanie na etapie kompilacji masy b(cid:228)(cid:246)dów, które inaczej wyst(cid:241)pi(cid:228)yby w czasie dzia(cid:228)ania programu. Typy kontenerowe zazwyczaj nazywa si(cid:246) typami ogólnymi (generycznymi), a deklaruje si(cid:246) je nast(cid:246)puj(cid:241)co: interface Box T { void box(T t); T unbox(); } 138 (cid:95) Rozdzia(cid:293) 4. System typów Javy Kup książkęPoleć książkę To oznacza, (cid:276)e interfejs Box jest konstrukcj(cid:241) ogóln(cid:241), w której mo(cid:276)na przechowywa(cid:232) dane do- wolnego typu. Sam w sobie interfejs nie jest kompletny — jest raczej ogólnym opisem ca(cid:228)ej ro- dziny interfejsów, po jednej dla ka(cid:276)dego typu, którego nazw(cid:246) mo(cid:276)na wpisa(cid:232) w miejsce pa- rametru T. Typy ogólne i parametry typów Wiesz ju(cid:276), jak u(cid:276)y(cid:232) typu ogólnego, aby zwi(cid:246)kszy(cid:232) poziom bezpiecze(cid:254)stwa programu przez wykorzystanie wiedzy dost(cid:246)pnej w czasie kompilacji w celu zapobie(cid:276)enia powstaniu b(cid:228)(cid:246)dów podczas dzia(cid:228)ania programu. W tym podrozdziale dok(cid:228)adniej poznasz w(cid:228)a(cid:264)ciwo(cid:264)ci typów ogólnych. Sk(cid:228)adnia T ma specjaln(cid:241) nazw(cid:246) — parametr typu — a inna nazwa typów ogólnych to typy parametryzowane. Odnosi si(cid:246) to do faktu, (cid:276)e typ kontenerowy (np. List) jest parametryzowany przez inny typ (przechowywanych w nim danych). Pisz(cid:241)c typ taki jak Map String, Integer , programista przypisuje parametrom typu konkretne warto(cid:264)ci. Przy tworzeniu typu parametryzowanego nale(cid:276)y uwa(cid:276)a(cid:232), aby nie zakodowa(cid:232) w nim (cid:276)ad- nych za(cid:228)o(cid:276)e(cid:254) dotycz(cid:241)cych parametrów typu. Zatem typ List w ogólnej wersji to List E . Para- metr typu E s(cid:228)u(cid:276)y jako symbol reprezentuj(cid:241)cy nazw(cid:246) rzeczywistego typu, którego dane pro- gramista b(cid:246)dzie przechowywa(cid:228) w tej strukturze. Parametry typu zawsze reprezentuj(cid:241) typy referencyjne. Nie mo(cid:276)na w ich miejsce wstawi(cid:232) typu prostego. Parametru typu mo(cid:276)na u(cid:276)ywa(cid:232) w sygnaturach i tre(cid:264)ci metod, tak jakby by(cid:228) prawdziwym ty- pem, np.: interface List E extends Collection E { boolean add(E e); E get(int index); // pozosta(cid:225)e metody zosta(cid:225)y pomini(cid:266)te } Nale(cid:276)y zauwa(cid:276)y(cid:232), (cid:276)e parametr typu E mo(cid:276)e by(cid:232) stosowany zarówno jako parametr typu zwrot- nego, jak i argumentu metody. Programista nie przyjmuje (cid:276)adnego za(cid:228)o(cid:276)enia, (cid:276)e typ (cid:228)adunku ma jakiekolwiek konkretne w(cid:228)a(cid:264)ciwo(cid:264)ci, a jedynie zak(cid:228)ada podstawow(cid:241) spójno(cid:264)(cid:232) — (cid:276)e typ wstawiony do kontenera zostanie te(cid:276) potem z niego pobrany. Sk(cid:293)adnia diamentowa W wyra(cid:276)eniu tworz(cid:241)cym egzemplarz typu ogólnego prawa strona przypisania zawiera powtó- rzenie warto(cid:264)ci parametru typu. Najcz(cid:246)(cid:264)ciej jest to niepotrzebne, poniewa(cid:276) kompilator mo(cid:276)e wydedukowa(cid:232) warto(cid:264)ci parametrów typu. W nowych wersjach Javy mo(cid:276)na opu(cid:264)ci(cid:232) powta- rzaj(cid:241)ce si(cid:246) warto(cid:264)ci typów przy u(cid:276)yciu tzw. sk(cid:228)adni diamentowej. Zobaczmy, jak zastosowa(cid:232) t(cid:246) sk(cid:228)adni(cid:246), przepisuj(cid:241)c jeden z wcze(cid:264)niejszych przyk(cid:228)adów: // utworzenie listy obiektów typu CenteredCircle List CenteredCircle shapes = new ArrayList (); Typy ogólne (cid:95) 139 Kup książkęPoleć książkę Jest to drobna poprawa, je(cid:264)li chodzi o rozwlek(cid:228)o(cid:264)(cid:232) instrukcji przypisania — uda(cid:228)o si(cid:246) zaoszcz(cid:246)- dzi(cid:232) wpisywania paru znaków. Do tematu dedukcji typów wrócimy jeszcze przy okazji opisu wyra(cid:276)e(cid:254) lambda pod koniec tego rozdzia(cid:228)u. Wymazywanie typów W podrozdziale „Metody domy(cid:264)lne” napisali(cid:264)my, (cid:276)e w(cid:228)a(cid:264)ciciele Javy bardzo dbaj(cid:241) o zgodno(cid:264)(cid:232) nowych wersji platformy ze starszymi. Dodatek typów ogólnych w Javie 5 jest kolejnym przy- k(cid:228)adem sytuacji, w której utrzymanie zgodno(cid:264)ci wstecznej sprawia(cid:228)o problemy. Najwa(cid:276)niejsz(cid:241) kwesti(cid:241) do rozwi(cid:241)zania by(cid:228)o to, jak stworzy(cid:232) system typów pozwalaj(cid:241)cy na u(cid:276)y- wanie starych, nieogólnych klas kolekcji razem z nowymi kolekcjami ogólnymi. Postanowiono zastosowa(cid:232) rzutowanie: List someThings = getSomeThings(); // Niebezpieczne rzutowanie, ale wiadomo, (cid:298)e zawarto(cid:286)(cid:252) listy someThings stanowi(cid:261) (cid:225)a(cid:276)cuchy. List String myStrings = (List String )someThings; To oznacza, (cid:276)e typy List i List String s(cid:241) ze sob(cid:241) zgodne przynajmniej na pewnym poziomie. Zgodno(cid:264)(cid:232) t(cid:246) w Javie uzyskano dzi(cid:246)ki wymazywaniu typów. Polega to na tym, (cid:276)e ogólne para- metry typu s(cid:241) widoczne tylko w czasie kompilacji, a kompilator javac je usuwa, dzi(cid:246)ki czemu w kodzie bajtowym s(cid:241) ju(cid:276) nieobecne1. Nieogólny typ List nazywa si(cid:246) typem surowym. Typów surowych nadal mo(cid:276)na u(cid:276)y- wa(cid:232), nawet je(cid:264)li maj(cid:241) uogólnione odpowiedniki. Jednak ich obecno(cid:264)(cid:232) prawie zawsze (cid:264)wiadczy o niskiej jako(cid:264)ci kodu. Sposób dzia(cid:228)ania mechanizmu wymazywania typów sprawia, (cid:276)e kompilator javac dzia(cid:228)a na nieco innym systemie typów ni(cid:276) maszyna wirtualna — szerzej tematem tym zaj(cid:246)li(cid:264)my si(cid:246) w podroz- dziale „Typy czasu kompilacji i wykonywania programu”. Ponadto wymazywanie typów uniemo(cid:276)liwia stosowanie pewnych definicji, które wydaj(cid:241) si(cid:246) po- prawne. W poni(cid:276)szym kodzie intencj(cid:241) programisty by(cid:228)o policzenie zamówie(cid:254) znajduj(cid:241)cych si(cid:246) w dwóch troch(cid:246) ró(cid:276)nych strukturach danych: // nie da si(cid:266) skompilowa(cid:252) interface OrderCounter { // nazwa odnosi si(cid:266) do listy numerów zamówie(cid:276) int totalOrders(Map String, List String orders); // nazwa odnosi si(cid:266) do liczby wszystkich z(cid:225)o(cid:298)onych do tej pory zamówie(cid:276) int totalOrders(Map String, Integer orders); } Ten kod wygl(cid:241)da na poprawny, a jednak nie przejdzie kompilacji. Problem polega na tym, (cid:276)e mimo i(cid:276) obie te metody wygl(cid:241)daj(cid:241) jak normalne przeci(cid:241)(cid:276)one wersje, to po wymazywaniu ty- pów ich sygnatury b(cid:246)d(cid:241) wygl(cid:241)da(cid:232) tak: int totalOrders(Map); 1 Pewne (cid:264)lady pozostaj(cid:241), co mo(cid:276)na sprawdzi(cid:232) przy u(cid:276)yciu refleksji. 140 (cid:95) Rozdzia(cid:293) 4. System typów Javy Kup książkęPoleć książkę Po wymazaniu typów pozostaje surowy typ kontenera, którym w tym przypadku jest Map. System wykonawczy nie b(cid:246)dzie w stanie odró(cid:276)ni(cid:232) tych dwóch metod po sygnaturach, przez co sk(cid:228)adnia ta jest niedozwolona w specyfikacji j(cid:246)zyka. Symbole wieloznaczne Typ parametryzowany, taki jak ArrayList T , nie umo(cid:276)liwia tworzenia egzemplarzy. Jest tak dlatego, (cid:276)e T to tylko parametr typu, symbol zast(cid:246)pczy rezerwuj(cid:241)cy miejsce dla nazwy praw- dziwego typu. Dopiero po wstawieniu w jego miejsce konkretnej warto(cid:264)ci (np. ArrayList String ) typ staje si(cid:246) kompletny i mo(cid:276)na tworzy(cid:232) jego egzemplarze. To powoduje problem, je(cid:264)li typ jest nieznany w czasie kompilacji, ale na szcz(cid:246)(cid:264)cie w systemie typów Javy istnieje na to sposób. Utworzono specjaln(cid:241) konstrukcj(cid:246) do jawnego oznaczania nie- znanego typu — ? . Jest to najprostszy przyk(cid:228)ad typu wieloznacznego (ang. wildcard) j(cid:246)zyka Java. Oto przyk(cid:228)ad wyra(cid:276)enia z u(cid:276)yciem typu nieznanego: ArrayList ? mysteryList = unknownList(); Object o = mysteryList.get(0); Jest to prawid(cid:228)owy kod w j(cid:246)zyku Java — ArrayList ? to w odró(cid:276)nieniu od formy ArrayList T kompletny typ zmiennej. Nic nie wiadomo o typie mo(cid:276)liwej zawarto(cid:264)ci listy mysteryList, ale nie sprawia to problemu w tym kodzie. Z u(cid:276)ywaniem typu nieznanego wi(cid:241)(cid:276)(cid:241) si(cid:246) pewne ograniczenia. Na przyk(cid:228)ad poni(cid:276)szy kod nie przejdzie kompilacji: // To nie przejdzie kompilacji. mysteryList.add(new Object()); Powód jest prosty — nie wiadomo, jakiego typu dane b(cid:246)d(cid:241) przechowywane w mysteryList! Gdyby si(cid:246) np. okaza(cid:228)o, (cid:276)e mysteryList jest egzemplarzem typu ArrayList String , to nie mo- gliby(cid:264)my si(cid:246) spodziewa(cid:232) mo(cid:276)liwo(cid:264)ci zapisania w tej li(cid:264)cie obiektów typu Object. Jedyna warto(cid:264)(cid:232), któr(cid:241) zawsze mo(cid:276)na wstawi(cid:232) do kontenera, to null — jak wiadomo, mo(cid:276)e ona zast(cid:241)pi(cid:232) ka(cid:276)dy typ referencyjny. Nie jest to jednak zbyt przydatne, wi(cid:246)c w specyfikacji Javy zabroniono tworzenia egzemplarzy kontenerów o nieznanym typie zawarto(cid:264)ci. Na przyk(cid:228)ad: // To nie przejdzie kompilacji. List ? unknowns = new ArrayList ? (); Bardzo wa(cid:276)ne zastosowanie typów nieznanych wynika z pytania: „Czy List String jest podtypem typu List Object ?”. Innymi s(cid:228)owy: czy mo(cid:276)na napisa(cid:232) taki kod? // Czy to jest dozwolone? List Object objects = new ArrayList String (); Na pierwszy rzut oka mo(cid:276)e si(cid:246) wydawa(cid:232), (cid:276)e ma to sens — String jest podklas(cid:241) klasy Object, wi(cid:246)c wiadomo, (cid:276)e ka(cid:276)dy element typu String jest jednocze(cid:264)nie poprawnym obiektem typu Object. Ale spójrz na poni(cid:276)szy kod: // Czy to jest dozwolone? List Object objects = new ArrayList String (); // Je(cid:298)eli tak, to co zrobi(cid:252) z tym? objects.add( new Object()); Ze wzgl(cid:246)du na to, (cid:276)e typ kontenera objects zosta(cid:228) zadeklarowany jako List Object , powinno da(cid:232) si(cid:246) wstawi(cid:232) do niego egzemplarz typu Object. Poniewa(cid:276) jednak rzeczywisty egzemplarz Typy ogólne (cid:95) 141 Kup książkęPoleć książkę tego kontenera przechowuje (cid:228)a(cid:254)cuchy, próba dodania obiektu typu Object oznacza(cid:228)aby nie- zgodno(cid:264)(cid:232) typów, wi(cid:246)c kod ten spowodowa(cid:228)by b(cid:228)(cid:241)d wykonywania programu. Nale(cid:276)y sobie u(cid:264)wiadomi(cid:232), (cid:276)e mimo i(cid:276) dozwolone (bo typ String dziedziczy po typie Object) jest napisanie takiego kodu: Object o = new String( X ); nie znaczy to, (cid:276)e analogiczna instrukcja dla kontenera ogólnego równie(cid:276) jest dozwolona: // To nie przejdzie kompilacji. List Object objects = new ArrayList String (); Inaczej mo(cid:276)na powiedzie(cid:232) w ten sposób, (cid:276)e List String nie jest podtypem typu List Object . Je(cid:264)li potrzebna jest taka relacja mi(cid:246)dzy kontenerami, nale(cid:276)y u(cid:276)y(cid:232) typu nieznanego: // To jest dozwolone. List ? objects = new ArrayList String (); To oznacza, (cid:276)e List String jest podtypem typu List ? , mimo i(cid:276) w takim przypisaniu jak powy(cid:276)sze zostan(cid:241) utracone pewne informacje o typie. Na przyk(cid:228)ad typem zwrotnym metody get() jest teraz Object. Ponadto nale(cid:276)y podkre(cid:264)li(cid:232), (cid:276)e List ? nie jest podtypem (cid:276)adnego typu List T dla jakiejkolwiek warto(cid:264)ci T. Typ nieznany sprawia niektórym programistom k(cid:228)opoty, wywo(cid:228)uj(cid:241)c pytania w rodzaju: „Czemu zamiast typu nieznanego nie mo(cid:276)na po prostu u(cid:276)y(cid:232) typu Object?”. Jak jednak pokazali- (cid:264)my, mo(cid:276)liwo(cid:264)(cid:232) tworzenia relacji podtypowych mi(cid:246)dzy typami ogólnymi wymaga istnienia poj(cid:246)cia typu nieznanego. Symbole wieloznaczne z ograniczeniami Tak naprawd(cid:246) typy wieloznaczne w j(cid:246)zyku Java nie ko(cid:254)cz(cid:241) si(cid:246) na typie nieznanym. Istniej(cid:241) jeszcze typy wieloznaczne z ograniczeniami, zwane te(cid:276) ograniczeniami parametrów typu. Umo(cid:276)liwiaj(cid:241) one okre(cid:264)lenie, jakie typy mog(cid:241) zosta(cid:232) wstawione w miejsce parametru typu. U(cid:276)ywa si(cid:246) ich do opisywania hierarchii dziedziczenia g(cid:228)ównie typów nieznanych i tworzenia stwierdze(cid:254) w rodzaju: „Nic nie wiem o tym typie oprócz tego, (cid:276)e musi implementowa(cid:232) interfejs List”. Stwierdzenie to nale(cid:276)a(cid:228)oby wyrazi(cid:232) jako ? extends List w parametrze typu. Mo(cid:276)e to by(cid:232) przydatna pomoc dla programisty, który zamiast u(cid:276)ywa(cid:232) kompletnie nieznanego typu, wie przynajmniej, jakie s(cid:241) jego niektóre w(cid:228)a(cid:264)ciwo(cid:264)ci. S(cid:228)owa kluczowego extends u(cid:276)ywa si(cid:246) zawsze, niezale(cid:276)nie od tego, czy typ ograniczaj(cid:241)cy jest typem klasowym, czy interfejsowym. Jest to przyk(cid:228)ad koncepcji zwanej wariancj(cid:241) typów, która jest ogóln(cid:241) teori(cid:241) opisuj(cid:241)c(cid:241) relacje mi(cid:246)dzy typami kontenerów i dziedziczeniem typów przechowywanych w nich danych. Kowariancja typów Oznacza, (cid:276)e typy kontenerów (cid:228)(cid:241)czy taka sama relacja jak typy przechowywanych w nich danych. Wyra(cid:276)a si(cid:246) to za pomoc(cid:241) s(cid:228)owa kluczowego extends. Kontrawariancja typów Oznacza, (cid:276)e typy kontenerów (cid:228)(cid:241)czy odwrotna relacja ni(cid:276) typy przechowywanych w nich danych. Wyra(cid:276)a si(cid:246) to za pomoc(cid:241) s(cid:228)owa kluczowego super. 142 (cid:95) Rozdzia(cid:293) 4. System typów Javy Kup książkęPoleć książkę Zasady te s(cid:241) wspominane w opisach typów kontenerów pe(cid:228)ni(cid:241)cych funkcj(cid:246) producentów lub konsumentów typów. Na przyk(cid:228)ad je(cid:276)eli Cat rozszerza Pet, to List Cat jest podtypem typu List ? extends Pet . List odgrywa rol(cid:246) producenta obiektów typu Cat i odpowiednim s(cid:228)owem kluczowym jest extends. W przypadku kontenera b(cid:246)d(cid:241)cego jedynie konsumentem egzemplarzy jakiego(cid:264) typu nale(cid:276)a(cid:228)oby u(cid:276)y(cid:232) s(cid:228)owa kluczowego super. Opisane zasady zosta(cid:228)y sformu(cid:228)owane przez Joshu(cid:246) Blocha i wyst(cid:246)puj(cid:241) pod nazw(cid:241) PECS (ang. Producer Extends, Consumer Super). W rozdziale 8. przekonasz si(cid:246), (cid:276)e kowariancja i kontrawariancja spotykane s(cid:241) w ca(cid:228)ej bibliotece kolekcji Javy. Ich najwa(cid:276)niejszym zadaniem jest zapewnienie poprawnego i niezaskakuj(cid:241)cego dzia(cid:228)ania typów ogólnych. Kowariancja tablic W pocz(cid:241)tkowych wersjach Javy, zanim w ogóle wprowadzono biblioteki kolekcji, problem dotycz(cid:241)cy wariancji typów kontenerowych wyst(cid:246)powa(cid:228) w odniesieniu do tablic. Bez wariancji typów trudno by(cid:228)o poprawnie napisa(cid:232) nawet tak prost(cid:241) metod(cid:246) jak sort(): Arrays. sort(Object[] a); Dlatego tablice w Javie s(cid:241) kowariantne — w tamtych czasach uznano to za z(cid:228)o konieczne, które niestety powodowa(cid:228)o powstanie luki w statycznym systemie typów: // Ten kod jest jak najbardziej poprawny. String[] words = { Witaj, (cid:258)wiecie! }; Object[] objects = words; // A niech to, b(cid:225)(cid:261)d wykonawczy. objects[0] = new Integer(42); Badania przeprowadzone na nowoczesnych otwartych bazach kodu sugeruj(cid:241), (cid:276)e kowariancja tablic jest bardzo rzadko spotykana i prawie zawsze stanowi usterk(cid:246) w projekcie j(cid:246)zyka pro- gramowania2. Powinno si(cid:246) jej unika(cid:232) przy pisaniu nowego kodu. Metody ogólne Metoda ogólna to taka metoda, która przyjmuje jako argumenty obiekty dowolnego typu re- ferencyjnego. Na przyk(cid:228)ad poni(cid:276)sza metoda imituje dzia(cid:228)anie operatora , (przecinek) z j(cid:246)zyka C, który s(cid:228)u(cid:276)y do (cid:228)(cid:241)czenia wyra(cid:276)e(cid:254) maj(cid:241)cych skutki uboczne: // Ta klasa nie jest ogólna. public class Utils public static T T comma(T a, T b) { return a; } } 2 Raoul-Gabriel Urma, Janina Voigt, Using the OpenJDK to Investigate Covariance in Java, „Java Magazine”, maj – czerwiec 2012, s. 44 – 47. Typy ogólne (cid:95) 143 Kup książkęPoleć książkę Mimo (cid:276)e w definicji metody u(cid:276)yto parametru typu, zawieraj(cid:241)ca j(cid:241) klasa nie jest ogólna. W tym przypadku specjaln(cid:241) sk(cid:228)adni(cid:246) zastosowano tylko po to, by zaznaczy(cid:232), (cid:276)e metody mo(cid:276)na u(cid:276)ywa(cid:232) w dowolny sposób oraz (cid:276)e jej typ zwrotny jest taki sam jak typ zwrotny argumentu. U(cid:348)ywanie i projektowanie typów ogólnych Przy pracy z typami ogólnymi w Javie czasami dobrze jest my(cid:264)le(cid:232) w kategoriach dwóch po- ziomów wtajemniczenia: Praktyk Praktyk u(cid:276)ywa istniej(cid:241)cych bibliotek ogólnych i tworzy stosunkowo proste w(cid:228)asne klasy ogólne. Programista taki powinien tak(cid:276)e posiada(cid:232) podstawow(cid:241) wiedz(cid:246) o wymazywaniu typów, poniewa(cid:276) niektóre cechy sk(cid:228)adni Javy trudno jest zrozumie(cid:232) bez przynajmniej ele- mentarnej wiedzy o tym, jak system wykonawczy obs(cid:228)uguje typy ogólne. Projektant Projektant nowych bibliotek zawieraj(cid:241)cych typy ogólne musi dysponowa(cid:232) o wiele szersz(cid:241) wiedz(cid:241) na ich temat. W specyfikacji wyst(cid:246)puj(cid:241) pewne trudniejsze cz(cid:246)(cid:264)ci, jak np. pe(cid:228)ny opis typów wieloznacznych, i s(cid:241) opisane zaawansowane zagadnienia, takie jak wiadomo(cid:264)ci o b(cid:228)(cid:246)dach „capture of”. Typy ogólne to jedna z najbardziej skomplikowanych cz(cid:246)(cid:264)ci specyfikacji j(cid:246)zyka Java. Zawiera wiele pu(cid:228)apek, o których nie ka(cid:276)dy programista musi wiedzie(cid:232), przynajmniej nie przy pierwszym zetkni(cid:246)ciem z t(cid:241) cz(cid:246)(cid:264)ci(cid:241) systemu. Typy czasu kompilacji i wykonywania programu Spójrz na poni(cid:276)szy fragment kodu: List String l = new ArrayList (); System.out.println(l); Mo(cid:276)na zada(cid:232) pytanie: jakiego typu jest l? Odpowied(cid:274) zale(cid:276)y od tego, czy interesuje nas l w cza- sie kompilacji (tzn. typ widziany przez kompilator javac), czy l w czasie dzia(cid:228)ania programu (typ widziany przez maszyn(cid:246) wirtualn(cid:241)). Dla kompilatora javac l b(cid:246)dzie list(cid:241) (cid:228)a(cid:254)cuchów i te informacje wykorzysta do sprawdzenia, czy nie ma b(cid:228)(cid:246)dów sk(cid:228)adniowych, np. próby dodania niedozwolonego typu. Natomiast dla maszyny wirtualnej l b(cid:246)dzie obiektem typu ArrayList, jak wida(cid:232) w wyniku in- strukcji println(). W czasie wykonywania programu zmienna l ma typ surowy dzi(cid:246)ki wy- mazywaniu typów. Oznacza to, (cid:276)e typy czasu wykonywania i kompilacji nieco si(cid:246) mi(cid:246)dzy sob(cid:241) ró(cid:276)ni(cid:241). Najdziw- niejsze jest jednak to, (cid:276)e pod pewnymi wzgl(cid:246)dami typ czasu wykonywania jest jednocze(cid:264)nie bardziej i mniej konkretny ni(cid:276) typ czasu kompilacji. Typ czasu wykonywania jest mniej specyficzny ni(cid:276) typ czasu kompilacji, poniewa(cid:276) utracona zosta(cid:228)a informacja o typie przechowywanych danych — znikn(cid:246)(cid:228)a w wyniku wymazywania typów i pozosta(cid:228) tylko typ surowy. 144 (cid:95) Rozdzia(cid:293) 4. System typów Javy Kup książkęPoleć książkę Typ czasu kompilacji jest mniej specyficzny ni(cid:276) typ czasu wykonywania, gdy(cid:276) nie wiadomo dok(cid:228)adnie, jaki konkretny typ b(cid:246)dzie mie(cid:232) l — wiadomo tylko, (cid:276)e b(cid:246)dzie to jaki(cid:264) typ zgodny z typem List. Wyliczenia i adnotacje W Javie istniej(cid:241) specjalne rodzaje klas i interfejsów odgrywaj(cid:241)ce specjalne role w systemie typów. S(cid:241) to typy wyliczeniowe i typy adnotacyjne, które zazwyczaj krócej nazywa si(cid:246) po prostu wyliczeniami (ang. enum) i adnotacjami (ang. annotation). Wyliczenia Wyliczenia s(cid:241) rodzajem klas o ograniczonej funkcjonalno(cid:264)ci i tylko niewielkiej liczbie mo(cid:276)li- wych warto(cid:264)ci. Za(cid:228)ó(cid:276)my np., (cid:276)e trzeba zdefiniowa(cid:232) typ do reprezentowania kolorów czerwonego, zielonego i niebieskiego oraz (cid:276)e s(cid:241) to jedyne dopuszczalne warto(cid:264)ci tego typu. Taki typ mo(cid:276)na zdefinio- wa(cid:232) przy u(cid:276)yciu s(cid:228)owa kluczowego enum: public enum PrimaryColor { // Na ko(cid:276)cu listy egzemplarzy nie musi by(cid:252) znaku ;. CZERWONY, ZIELONY, NIEBIESKI } Do pól wyliczenia PrimaryColor mo(cid:276)na si(cid:246) teraz odwo(cid:228)ywa(cid:232) tak, jakby by(cid:228)y polami statycznymi: PrimaryColor.CZERWONY, PrimaryColor.ZIELONY i PrimaryColor.NIEBIESKI. W innych j(cid:246)zykach programowania, np. C++, do tego celu najcz(cid:246)(cid:264)ciej u(cid:276)ywa si(cid:246) sta(cid:228)ych warto(cid:264)ci ca(cid:228)kowitoliczbowych, ale technika zastosowana w Javie zapewnia lepsze bez- piecze(cid:254)stwo typów i wi(cid:246)ksz(cid:241) elastyczno(cid:264)(cid:232). Na przyk(cid:228)ad jako (cid:276)e wyliczenia s(cid:241) specjalnym rodzajem klas, mog(cid:241) zawiera(cid:232) pola i metody sk(cid:228)adowe. Je(cid:264)li maj(cid:241) tre(cid:264)(cid:232) g(cid:228)ówn(cid:241) (sk(cid:228)a- daj(cid:241)c(cid:241) si(cid:246) z pól i metod), to na ko(cid:254)cu listy sk(cid:228)adowych wymagany jest (cid:264)rednik. Za(cid:228)ó(cid:276)my np., (cid:276)e potrzebne jest wyliczenie zawieraj(cid:241)ce kilka wielok(cid:241)tów foremnych (figur geometrycznych, w których wszystkie boki i k(cid:241)ty s(cid:241) równe), na których mo(cid:276)na wykonywa(cid:232) pewne dzia(cid:228)ania (za pomoc(cid:241) metod). Mo(cid:276)na w tym celu utworzy(cid:232) wyliczenie przyjmuj(cid:241)ce warto(cid:264)(cid:232) jako parametr: public enum RegularPolygon { // W wyliczeniach z parametrami (cid:286)rednik jest potrzebny. TRIANGLE(3), SQUARE(4), PENTAGON(5), HEXAGON(6); private Shape shape; public Shape getShape() { return shape; } private RegularPolygon( int sides) { switch (sides) { case 3: // Zak(cid:225)adamy, (cid:298)e mamy kilka ogólnych konstruktorów // kszta(cid:225)tów, które pobieraj(cid:261) jako parametry // d(cid:225)ugo(cid:286)(cid:252) boku i miar(cid:266) k(cid:261)ta w stopniach. shape = new Triangle(1, 1, 1, 60, 60, 60); Wyliczenia i adnotacje (cid:95) 145 Kup książkęPoleć książkę break; case 4: shape = new Rectangle(1, 1); break; case 5: shape = new Pentagon(1, 1, 1, 1, 1, 108, 108, 108, 108, 108); break; case 6: shape = new Hexagon(1, 1, 1, 1, 1, 1, 120, 120, 120, 120, 120, 120); break; } } } Parametry te (w tym przyk(cid:228)adzie tylko jeden) s(cid:241) przekazywane do konstruktora w celu utworzenia poszczególnych egzemplarzy wyliczenia. Jako (cid:276)e egzemplarze wyliczenia s(cid:241) two- rzone przez system wykonawczy Javy i nie mog(cid:241) by(cid:232) tworzone z zewn(cid:241)trz, konstruktor zosta(cid:228) zadeklarowany jako prywatny. Wyliczenia maj(cid:241) pewne specjalne w(cid:228)a(cid:264)ciwo(cid:264)ci: (cid:120) Wszystkie niejawnie rozszerzaj(cid:241) klas(cid:246) java.lang.Enum. (cid:120) Nie mog(cid:241) by(cid:232) ogólne. (cid:120) Mog(cid:241) implementowa(cid:232) interfejsy. (cid:120) Nie mog(cid:241) by(cid:232) rozszerzane. (cid:120) Mog(cid:241) zawiera(cid:232) metody abstrakcyjne tylko wtedy, gdy wszystkie warto(cid:264)ci wyliczenia s(cid:241) zaimplementowane. (cid:120) Mog(cid:241) mie(cid:232) tylko prywatny konstruktor. Adnotacje Adnotacje to specjalny rodzaj interfejsu, który jak sama nazwa wskazuje, opatruje przypisem pewn(cid:241) cz(cid:246)(cid:264)(cid:232) programu. We(cid:274)my np. adnotacj(cid:246) @Override. By(cid:228)a ju(cid:276) u(cid:276)ywana w niektórych wcze(cid:264)niejszych przyk(cid:228)adach i mo(cid:276)e zastanawia(cid:228)e(cid:264) si(cid:246), co to jest. Najkrótsza i do(cid:264)(cid:232) zaskakuj(cid:241)ca odpowied(cid:274) jest taka, (cid:276)e adnotacja ta nic nie robi. Nieco d(cid:228)u(cid:276)sza (i mniej powa(cid:276)na) odpowied(cid:274) jest taka, (cid:276)e @Override, jak wszystkie inne adnotacje, nie wywo(cid:228)uje bezpo(cid:264)rednich efektów, tylko s(cid:228)u(cid:276)y jako dodatkowa informacja na temat metody, której dotyczy — w tym przypadku oznacza, (cid:276)e metoda przes(cid:228)ania metod(cid:246) z nadklasy. Jest to przydatna wskazówka dla kompilatorów i zintegrowanych (cid:264)rodowisk programistycz- nych — je(cid:264)li programista pomyli si(cid:246) przy wpisywaniu nazwy przes(cid:228)anianej metody, to obec- no(cid:264)(cid:232) adnotacji @Override przy metodzie, która nie przes(cid:228)ania (cid:276)adnej innej metody, zaalarmuje kompilator, (cid:276)e co(cid:264) jest nie tak. Adnotacje nie mog(cid:241) zmienia(cid:232) semantyki programu, a ich jedynym zadaniem jest dostarcza- nie dodatkowych metainformacji. (cid:263)ci(cid:264)le rzecz bior(cid:241)c, oznacza to, (cid:276)e adnotacje nie powinny wp(cid:228)ywa(cid:232) na sposób wykonywania programu, a tylko przekazywa(cid:232) informacje dla kompilatora i innych narz(cid:246)dzi dzia(cid:228)aj(cid:241)cych przed rozpocz(cid:246)ciem wykonywania programu. 146 (cid:95) Rozdzia(cid:293) 4. System typów Javy Kup książkęPoleć książkę Kilka podstawowych adnotacji platformy jest zdefiniowanych w pakiecie java.lang. Pocz(cid:241)tko- wo istnia(cid:228)y tylko adnotacje @Override, @Deprecated i @SuppressWarnings, oznaczaj(cid:241)ce odpowiednio przes(cid:228)oni(cid:246)cie metody, metod(cid:246), której u(cid:276)ywania si(cid:246) nie zaleca, oraz to, (cid:276)e dana metoda generuje pewne ostrze(cid:276)enia, które nale(cid:276)y st(cid:228)umi(cid:232). W Javie 7 dodano do tego zestawu adnotacj(cid:246) @SafeVarargs (rozszerzone t(cid:228)umienie ostrze(cid:276)e(cid:254) dla metod o zmiennej liczbie argumentów), a w Javie 8 — @FunctionalInterface. Adnotacja @FunctionalInterface oznacza, (cid:276)e dany interfejs mo(cid:276)e by(cid:232) u(cid:276)ywany jako cel dla wyra(cid:276)enia lambda — jest przydatnym znacznikiem, chocia(cid:276) nie ma obowi(cid:241)zku jego stosowania. W porównaniu ze zwyk(cid:228)ymi interfejsami adnotacje maj(cid:241) pewne specjalne w(cid:228)a(cid:264)ciwo(cid:264)ci: (cid:120) Wszystkie niejawnie rozszerzaj(cid:241) interfejs java.lang.annotation.Annotation. (cid:120) Nie mog(cid:241) by(cid:232) ogólne. (cid:120) Nie mog(cid:241) rozszerza(cid:232) (cid:276)adnego innego interfejsu. (cid:120) Mog(cid:241) definiowa(cid:232) tylko metody nieprzyjmuj(cid:241)ce argumentów. (cid:120) Nie mog(cid:241) definiowa(cid:232) metod zg(cid:228)aszaj(cid:241)cych wyj(cid:241)tki. (cid:120) Maj(cid:241) ograniczony zestaw typów zwrotnych dla metod. (cid:120) Mog(cid:241) mie(cid:232) domy(cid:264)ln(cid:241) warto(cid:264)(cid:232) zwrotn(cid:241) dla metod. Definiowanie w(cid:293)asnych adnotacji Definiowanie w(cid:228)asnych adnotacji do u(cid:276)ytku w swoich programach nie jest trudne. S(cid:228)u(cid:276)y do tego s(cid:228)owo kluczowe @interface, którego u(cid:276)ywa si(cid:246) bardzo podobnie jak s(cid:228)ów kluczowych class i interface. Kluczem do pisania w(cid:228)asnych adnotacji jest wykorzystanie „metaadnotacji”. Jest to specjalny rodzaj adnotacji wyst(cid:246)puj(cid:241)cych w definicjach nowych typów adnotacji. Metaadnotacje s(cid:241) zdefiniowane w pakiecie java.lang.annotation i umo(cid:276)liwiaj(cid:241) zdefiniowanie zasady dotycz(cid:241)cej tego, gdzie dany typ adnotacji mo(cid:276)e by(cid:232) u(cid:276)ywany oraz jak powinien by(cid:232) traktowany przez kompilator i system wykonawczy. Istniej(cid:241) dwie podstawowe metaadnotacje, które s(cid:241) w zasadzie niezb(cid:246)dne przy tworzeniu nowego typu adnotacji: @Target i @Retention. Obie przyjmuj(cid:241) warto(cid:264)ci reprezentowane jako wyliczenia. Metaadnotacja @Target okre(cid:264)la, gdzie dana adnotacja mo(cid:276)e by(cid:232) u(cid:276)ywana w kodzie (cid:274)ród(cid:228)owym. Wyliczenie ElementType ma nast(cid:246)puj(cid:241)cy zestaw dopuszczalnych warto(cid:264)ci: TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER oraz TYPE_USE. Druga metaadnotacja to @Retention. Okre(cid:264)la ona, w jaki sposób kompilator javac i system wy- konawczy Javy maj(cid:241) przetwarza(cid:232) dan(cid:241) adnotacj(cid:246). Mo(cid:276)e mie(cid:232) jedn(cid:241) z trzech warto(cid:264)ci reprezento- wanych przez wyliczenie RetentionPolicy: SOURCE Adnotacje z t(cid:241) zasad(cid:241) zatrzymania s(cid:241) odrzucane przez kompilator javac w czasie kompilacji. Wyliczenia i adnotacje (cid:95) 147 Kup książkęPoleć książkę CLASS To oznacza, (cid:276)e adnotacja b(cid:246)dzie obecna w pliku klasy, ale niekoniecznie b(cid:246)dzie dost(cid:246)pna w czasie wykonywania programu przez maszyn(cid:246) wirtualn(cid:241). Ustawienia tego u(cid:276)ywa si(cid:246) rzadko, ale czasami mo(cid:276)na je spotka(cid:232) w narz(cid:246)dziach do statycznej analizy kodu bajtowego. RUNTIME To oznacza, (cid:276)e adnotacja b(cid:246)dzie dost(cid:246)pna w kodzie u(cid:276)ytkownika w czasie dzia(cid:228)ania pro- gramu (przy u(cid:276)yciu refleksji). Spójrz na prosty przyk(cid:228)ad definicji adnotacji o nazwie @Nickname, która umo(cid:276)liwia programi(cid:26
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Java w pigułce. Wydanie VI
Autor:
,

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: