Java 1 5 Tiger Zapiski programisty jatinp


IDZ DO
IDZ DO
PRZYKŁADOWY ROZDZIAŁ
PRZYKŁADOWY ROZDZIAŁ
Java 1.5 Tiger.
SPIS TRERCI
SPIS TRERCI
Zapiski programisty
KATALOG KSIĄŻEK
KATALOG KSIĄŻEK
Autorzy: Brett McLaughlin, David Flanagan
Tłumaczenie: Jaromir Senczyk
KATALOG ONLINE
KATALOG ONLINE
ISBN: 83-246-0048-5
Tytuł oryginału: Java 1.5 Tiger A Developers Notebook
ZAMÓW DRUKOWANY KATALOG
ZAMÓW DRUKOWANY KATALOG
Format: B5, stron: 224
TWÓJ KOSZYK
TWÓJ KOSZYK
Zobacz, co ma do zaoferowania najnowsza wersja Javy
DODAJ DO KOSZYKA
DODAJ DO KOSZYKA
" Zdefiniuj własne klasy generyczne
" Zastosuj w programach nowe typy danych
" Poznaj nowe mechanizmy obsługi współbieżnoSci
CENNIK I INFORMACJE
CENNIK I INFORMACJE
Najnowsza wersja języka i Srodowiska Java, nosząca nazwę Tiger, to nie aktualizacja,
ZAMÓW INFORMACJE
ZAMÓW INFORMACJE
ale prawie nowy język programowania. Wprowadzono do niej ponad sto poprawek,
O NOWORCIACH
O NOWORCIACH
zmian i udoskonaleń oraz nowe biblioteki i interfejsy programistyczne. Java 1.5 Tiger
oferuje programistom dziesiątki nowych możliwoSci. Nowa specyfikacja języka jest
ZAMÓW CENNIK
ZAMÓW CENNIK
ogromnym tomiskiem, którego lektura znuży nawet największego fanatyka Javy.
Kontakt z najnowszym wcieleniem tego popularnego języka programowania najlepiej
zacząć od poznania tego, co faktycznie jest w nim nowe.
CZYTELNIA
CZYTELNIA
 Java 1.5 Tiger. Notatnik programisty to książka, zawierająca notatki prawdziwych
fachowców, którzy analizowali nową wersję Javy jeszcze przed jej publiczną
FRAGMENTY KSIĄŻEK ONLINE
FRAGMENTY KSIĄŻEK ONLINE
prezentacją. Przedstawia wszystkie nowoSci Javy 1.5 zilustrowane ponad
pięćdziesięcioma przykładami kodu xródłowego. Czytając ją, poznasz zasady
stosowania generycznoSci, zrozumiesz działanie mechanizmów automatycznego
opakowywania i rozpakowywania, nauczysz się korzystać z nowych sposobów
formatowania tekstów i opanujesz posługiwanie się typami wyliczeniowymi
i adnotacjami.
" GenerycznoSć i typy parametryczne
" Tworzenie i stosowanie typów wyliczeniowych
" Automatyczne opakowywanie i rozpakowywanie
" Wykorzystywanie list argumentów o zmiennej długoSci
" Instrukcja for/in
Wydawnictwo Helion
" Obsługa i synchronizacja wątków
ul. Chopina 6
Poznaj i ujarzmij siłę  tygrysa
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
Spis treści
Seria  Zapiski programisty .................................................................. 7
Wstęp .................................................................................................. 13
Rozdział 1. Co nowego? ....................................................................... 21
Tablice ................................................................................................ 22
Kolejki .................................................................................................25
Kolejki uporządkowane i komparatory ................................................28
Przesłanianie typów zwracanych ........................................................ 30
Wykorzystanie zalet Unicode ..............................................................32
Klasa StringBuilder .............................................................................34
Rozdział 2. Generyczność .................................................................... 37
Stosowanie list bezpiecznych typologicznie ......................................... 38
Stosowanie map bezpiecznych typologicznie .......................................41
Przeglądanie typów parametrycznych ................................................ 42
Akceptowanie typów parametrycznych jako argumentów ..................45
Zwracanie typów parametrycznych .................................................... 46
Stosowanie typów parametrycznych jako parametrów typu ............... 47
Ostrzeżenia lint ................................................................................... 48
Generyczność i konwersje typów .........................................................49
Stosowanie wzorców typów ................................................................53
3
Tworzenie typów generycznych ..........................................................55
Ograniczanie parametrów typu ............................................................56
Rozdział 3. Typy wyliczeniowe .............................................................59
Tworzenie typu wyliczeniowego ..........................................................60
Typy wyliczeniowe rozwijane w miejscu deklaracji ............................66
Przeglądanie typów wyliczeniowych ...................................................67
Typy wyliczeniowe w instrukcjach wyboru .........................................68
Mapy typów wyliczeniowych ...............................................................73
Zbiory typów wyliczeniowych .............................................................75
Dodawanie metod do typów wyliczeniowych .......................................78
Implementacja interfejsów i typy wyliczeniowe ..................................82
Ciała klas specyficzne dla poszczególnych wartości ............................83
Samodzielne definiowanie typów wyliczeniowych ...............................86
Rozszerzanie typu wyliczeniowego .....................................................87
Rozdział 4. Automatyczne opakowywanie i rozpakowywanie ..............89
Przekształcanie wartości typów podstawowych
w obiekty typów opakowujących .......................................................90
Przekształcanie obiektów typów opakowujących
w wartości typów podstawowych ......................................................92
Operacje zwiększania i zmniejszania dla typów opakowujących .........93
Boolean i boolean .................................................................................94
Wyrażenia warunkowe i rozpakowywanie ..........................................95
Instrukcje sterujące i rozpakowywanie ................................................97
Wybór metody przeciążonej ................................................................98
Rozdział 5. Listy argumentów o zmiennej długości ............................101
Tworzenie list argumentów o zmiennej długości ...............................103
Przeglądanie list argumentów o zmiennej długości ...........................106
Listy argumentów o zerowej długości ................................................108
Obiekty jako argumenty zamiast typów podstawowych .....................110
Zapobieganie automatycznej konwersji tablic ....................................112
4 Spis treści
Rozdział 6. Adnotacje ........................................................................ 115
Stosowanie standardowych typów adnotacji .....................................116
Adnotowanie przesłaniania metody .................................................. 119
Adnotowanie przestarzałej metody ...................................................121
Wyłączanie ostrzeżeń ....................................................................... 123
Tworzenie własnych typów adnotacji ................................................125
Adnotowanie adnotacji ...................................................................... 128
Definiowanie elementu docelowego dla typu adnotacji ...................... 129
Zachowywanie typu adnotacji ...........................................................130
Dokumentowanie typów adnotacji .....................................................131
Konfigurowanie dziedziczenia adnotacji ............................................ 134
Refleksje i adnotacje .......................................................................... 137
Rozdział 7. Instrukcja for/in .............................................................. 143
Pozbywanie się iteratorów ................................................................144
Przeglądanie tablic ............................................................................ 147
Przeglądanie kolekcji ........................................................................148
Zapobieganie niepotrzebnemu rzutowaniu ........................................ 150
Adaptacja klas do pracy z pętlą for/in ............................................... 152
Określanie pozycji na liście i wartości zmiennej ...............................157
Usuwanie elementów listy w pętli for/in ........................................... 158
Rozdział 8. Import składowych statycznych ...................................... 161
Importowanie składowych statycznych .............................................162
Stosowanie wzorców podczas importowania .....................................164
Importowanie wartości typów wyliczeniowych .................................165
Importowanie wielu składowych o tej samej nazwie ......................... 167
Przesłanianie importu składowych statycznych ................................ 169
Rozdział 9. Formatowanie ................................................................. 171
Tworzenie instancji klasy Formatter .................................................171
Formatowanie danych wyjściowych .................................................172
Spis treści 5
Stosowanie metody format() ..............................................................178
Stosowanie metody printf() ................................................................180
Rozdział 10. Wątki .............................................................................181
Obsługa wyjątków .............................................................................182
Kolekcje i wątki .................................................................................186
Stosowanie kolejek blokujących .........................................................189
Określanie limitów czasu dla blokowania ..........................................193
Separacja logiki wątku od logiki wykonania ......................................195
Stosowanie interfejsu ExecutorService ..............................................197
Stosowanie obiektów Callable ............................................................199
Wykonywanie zadań bez użycia interfejsu ExecutorService .............201
Planowanie zadań .............................................................................202
Zaawansowana synchronizacja ........................................................205
Typy atomowe ...................................................................................207
Blokowanie a synchronizacja ............................................................209
Skorowidz ..........................................................................................215
6 Spis treści
ROZDZIAA 4
Automatyczne
opakowywanie
i rozpakowywanie
W tym rozdziale:
Przekształcanie wartości typów podstawowych w obiekty typów opa-
kowujących
Przekształcanie obiektów typów opakowujących w wartości typów
podstawowych
Operacje zwiększania i zmniejszania dla typów opakowujących
Boolean i boolean
Wyrażenia warunkowe i rozpakowywanie
Instrukcje sterujące i rozpakowywanie
Wybór metody przeciążonej
Gdy rozpoczynamy naukę programowania w języku Java, jedna z pierw-
szych lekcji zawsze dotyczy obiektów. Można powiedzieć, że klasa
java.lang.Object stanowi kamień węgielny języka Java. Praktycznie
99% kodu posługuje się tą klasą lub jej klasami pochodnymi. Jednak po-
zostały 1% może nam sprawiać sporo kłopotów, wymagając ciągłego
przekształcania obiektów na wartości typów podstawowych i z powrotem.
89
Do typów podstawowych w języku Java należą int, short, char i tym
podobne. Ich wartości nie są obiektami. W rezultacie w języku Java udo-
stępniono dodatkowo klasy opakowujące, takie jak Integer, Short czy
Character, które stanowią obiektowe wersje typów podstawowych. Jed-
nak ciągłe przekształcanie obiektów w wartości typów podstawowych
i z powrotem bywa irytujące. Nagle okazuje się, że kod programu zosta-
je zdominowany przez wywołania metod w rodzaju intValue().
W wersji Tiger dostarczono rozwiązania tego problemu za pomocą dwóch
nowych mechanizmów konwersji: opakowywania i rozpakowywania.
W obu przypadkach nazwy wspomnianych mechanizmów można do-
datkowo opatrzyć przymiotnikiem  automatyczne .
Przekształcanie wartości
typów podstawowych
w obiekty typów opakowujących
Literały w języku Java zawsze są jednego z typów podstawowych. Na
przykład wartość 0 jest typu int i może zostać zamieniona w obiekt za
pomocą następującego kodu:
Integer i = new Integer(0);
W wersji Tiger wyeliminowano konieczność tworzenia takiego kodu.
Jak to osiągnąć?
Nareszcie możemy zapomnieć o ręcznych konwersjach i pozwolić wy-
konywać je maszynie wirtualnej Java:
Integer i = 0;
Zamieni ona automatycznie wartość typu podstawowego w obiekt opa-
kowujący. Ta sama konwersja odbywa się też w przypadku zmiennych
typów podstawowych:
int foo = 0;
Integer integer = foo;
Aby przekonać się o przydatności tego rozwiązania, należy spróbować
skompilować powyższy fragment za pomocą jednej z wersji języka
90 Rozdział 4: Automatyczne opakowywanie i rozpakowywanie
wcześniejszych od wersji Tiger. Uzyskamy wtedy dość dziwne komuni-
katy o błędach:
compile-1.4:
Przykłady
[echo] Compiling all Java files...
zamieszczone
[javac] Compiling 1 source file to classes
w tym rozdziale
[javac] src\com\oreilly\tiger\ch04\Conversion.java:6: incompatible
możemy
types
skompilować
[javac] found : int
z opcją
[javac] required: java.lang.Integer
-source 1.4,
[javac] Integer i = 0;
używając celu
[javac] ^
compile-1.4.
[javac] src\com\oreilly\tiger\ch04\ConversionTester.java:9:
incompatible types
[javac] found : int
[javac] required: java.lang.Integer
[javac] Integer integer = foo;
[javac] ^
[javac] 2 errors
Błędy te znikną w  magiczny sposób w wersji Tiger, gdy zastosujemy
opcję kompilacji -source 1.5.
Jak to działa?
Wartości typów podstawowych zostają automatycznie opakowane. Przez
opakowanie rozumiemy konwersję typu podstawowego do odpowiadają-
cego mu obiektowego typu opakowującego: Boolean, Byte, Short, Cha-
racter, Integer, Long, Float lub Double. Ponieważ konwersja ta zacho-
dzi automatycznie, nazywamy ją automatycznym opakowywaniem.
W języku Java, oprócz opakowania wartości, może również dojść do
konwersji poszerzającej typ:
Number n = 0.0f;
Istnieje możliwość
W tym przypadku literał zostanie najpierw opakowany obiektem typu
jawnego zażądania
konwersji
Float, którego typ zostanie następnie poszerzony do Number.
opakowującej
w sposób
Specyfikacja języka Java informuje, że pewne wartości typów prostych
przypominający
są zawsze opakowywane za pomocą tych samych obiektów opakowują-
rzutowanie.
cych, które nie mogą być modyfikowane. Obiekty te są przechowywane
Aatwiej jednak
pozostawić
w buforze i używane wielokrotnie. Do wartości traktowanych w ten spo-
wykonanie tego
sób należą true i false, wszystkie wartości typu byte, wartości typów
zadania maszynie
short i int należące do przedziału od -128 do 127 oraz wszystkie znaki wirtualnej.
Przekształcanie wartości typów podstawowych w obiekty typów opakowujących 91
typu char o kodach od \u0000 do \u007F. Jednak ponieważ wszystko to
odbywa się automatycznie, jest to właściwie tylko szczegół implementa-
cji i nie musimy się tym przejmować.
Przekształcanie obiektów
typów opakowujących
w wartości typów podstawowych
Oprócz konwersji wartości typów podstawowych do typów opakowują-
cych, w wersji Tiger dokonywana jest również konwersja w kierunku
przeciwnym. Podobnie jak opakowywanie, również rozpakowywanie nie
wymaga interwencji programisty.
Jak to osiągnąć?
Poniżej przedstawiony został prosty przykład kodu, w którym zachodzi
opakowywanie i rozpakowywanie bez żadnych dodatkowych instrukcji:
// Opakowywanie
int foo = 0;
Integer integer = foo;
// Rozpakowywanie
int bar = integer;
Integer counter = 1; // opakowywanie
int counter2 = counter; // rozpakowywanie
Zupełnie proste, prawda?
A co&
& z wartością null? Ponieważ wartość null dozwolona jest dla dowol-
nego obiektu i tym samym dowolnego typu opakowującego, poniższy kod
jest poprawny:
Integer i = null;
int j = i;
Podstawienie wartości null do i jest dozwolone. Następnie i zostaje
rozpakowane do j. Ponieważ null nie jest poprawną wartością typu
podstawowego, zostaje wygenerowany wyjątek NullPointerException.
92 Rozdział 4: Automatyczne opakowywanie i rozpakowywanie
Operacje zwiększania i zmniejszania
dla typów opakowujących
Jeśli zastanowimy się nad konsekwencjami opakowywania i rozpako-
wywania, dojdziemy do wniosku, że są one daleko idące. Na przykład
każda operacja dostępna dla typu podstawowego powinna być również
dostępna dla typu opakowującego i na odwrót. Przykładem mogą być
operacje zwiększania i zmniejszania (++ i --), które obecnie działają
także w przypadku typów opakowujących.
Jak to osiągnąć?
Nie jest to trudne:
Integer counter = 1;
while (true) {
System.out.printf("Iteracja %d%n", counter++);
if (counter > 1000) break;
}
Zmienna counter traktowana jest w tym przykładzie jak zmienna typu int.
Jak to działa?
W rzeczywistości w naszym przykładzie zdarzyło się więcej, niż można
by przypuszczać. Wezmy następujący jego fragment:
counter++
Przypomnijmy, że counter jest typu Integer. Obiekt counter został więc
najpierw automatycznie rozpakowany do wartości typu int, który wy-
magany jest przez operator ++.
WSKAZÓWKA
Zauważmy, że operator ++ nie został przystosowany do działania
z typami opakowującymi. Kod ten działa jedynie dzięki automatycz-
nemu rozpakowywaniu.
Dopiero po rozpakowaniu wykonana zostaje operacja zwiększania. Na-
stępnie nowa wartość musi zostać z powrotem umieszczona w obiekcie
Operacje zwiększania i zmniejszania dla typów opakowujących 93
counter, co wymaga wykonania operacji opakowywania. A wszystko to
odbywa się niezauważalnie, w ułamku sekundy!
W naszym przykładzie również w przypadku porównania obiektu coun-
ter z literałem 1000 zachodzi automatyczne opakowywanie.
Boolean i boolean
Typ boolean wyróżnia się wśród typów podstawowych dostępnością
operatorów logicznych, takich jak ! (negacja), || (alternatywa) i && (ko-
niunkcja). Dzięki automatycznemu rozpakowywaniu możemy stosować
je także dla obiektów typu Boolean.
Jak to osiągnąć?
Za każdym razem, gdy w wyrażeniu zawierającym operator !, || lub &&
pojawia się obiekt Boolean, zostaje on automatycznie rozpakowany do
wartości typu boolean, która zostaje użyta do wyznaczenia wartości ca-
łego wyrażenia.
Boolean case1 = true;
Boolean case2 = true;
boolean case3 = false;
Boolean result = (case1 || case2) && case3;
Wartość typu boolean będąca wynikiem wyrażenia zostanie w tym
przypadku z powrotem opakowana za pomocą obiektu typu Boolean.
Wartości typów
A co&
podstawowych
zostają opakowane
& z bezpośrednimi porównaniami obiektów? Działają one w taki sam
w porównaniach
za pomocą
sposób jak dotąd:
operatora ==.
Integer i1 = 256;
W przypadku
Integer i2 = 256;
operatorów takich
jak <, >= i tym
if (i1 == i2) System.out.println("Równe!");
podobnych,
else System.out.println("Różne!");
typy opakowujące
zostają
Wynikiem wykonania tego kodu, przynajmniej przez moją maszynę
rozpakowane
wirtualną, jest komunikat "Różne!". W tym przykładzie nie zachodzi
do typów
podstawowych. operacja rozpakowywanie. Literał 256 zostaje opakowany za pomocą
94 Rozdział 4: Automatyczne opakowywanie i rozpakowywanie
dwóch różnych obiektów typu Integer (przynajmniej przez moją ma-
szynę), a następnie obiekty te zostają porównane za pomocą operatora
==. Wynikiem porównania jest false, ponieważ porównywane są dwie
różne instancje mające różne adresy w pamięci. Ponieważ po obu stro-
nach operatora == znajdują się obiekty, nie zachodzi operacja rozpako-
wywania.
OSTRZEŻENIE
Nie należy polegać na wyniku działania tego przykładu, zamieści-
łem go jedynie dla ilustracji. Inne implementacje maszyny wirtual-
nej Java mogą optymalizować kod i stworzyć jedną, wspólną instan-
cję dla obu literałów. W takim przypadku wynikiem wyrażenia
zawierającego operator porównania == będzie wartość logiczna true.
Ale uwaga! Przypomnijmy (z podrozdziału  Przekształcanie wartości
typów podstawowych w obiekty typów opakowujących ), że niektóre
wartości typów podstawowych są opakowywane za pomocą obiektów,
które nie mogą być modyfikowane. Dlatego też wynik działania poniż-
szego kodu może stanowić pewną niespodziankę:
Integer i1 = 100;
Integer i2 = 100;
if (i1 == i2) System.out.println("Równe!");
else System.out.println("Różne!");
W tym przypadku wynikiem tym będzie komunikat "Równe!". Przypo-
mnijmy, że wartości typu int z zakresu od -128 do 127 są opakowywa-
ne właśnie za pomocą stałych, niemodyfikowalnych obiektów. Maszyna
wirtualna używa więc tego samego obiektu dla i1 i i2. W rezultacie wy-
nikiem porównania jest wartość true. Należy o tym pamiętać, ponieważ
przeoczenia tego faktu mogą powodować trudne do znalezienia błędy.
Wyrażenia warunkowe i rozpakowywanie
Jedną z dziwniejszych możliwości języka Java jest operator warunkowy
zwany również operatorem ternarnym. Operator ten stanowi wersję
instrukcji warunkowej if/else reprezentowaną za pomocą znaku ?.
Wyrażenia warunkowe i rozpakowywanie 95
Ponieważ operator ten wymaga wyznaczenia wartości wyrażeń, rów-
nież jest związany z mechanizmem automatycznego opakowywania
wprowadzonym w wersji Tiger. Operatora tego możemy używać dla
różnych typów.
Jak to osiągnąć?
Oto składnia operatora warunkowego:
[wyrażenie warunkowe] ? [wyrażenie1] : [wyrażenie2]
Jeśli wynikiem wyrażenia [wyrażenie warunkowe] jest wartość lo-
giczna true, opracowane zostanie [wyrażenie1]; w przeciwnym razie
[wyrażenie2]. W wersjach poprzedzających wersję Tiger wynikiem wy-
rażenia [wyrażenie warunkowe] musiała być wartość typu boolean. By-
ło to mało wygodne w sytuacji, gdy jakaś metoda zwracała obiekty typu
opakowującego Boolean lub obiekt tego typu był wynikiem wyrażenia. W
wersji Tiger nie stanowi to już problemu, ponieważ operator działa dla
wartości będących wynikiem rozpakowania obiektów Boolean:
Boolean arriving = false;
Boolean late = true;
System.out.println(arriving ? (late ? "Najwyższy czas!" : "Cześć!") :
(late ? "Pośpiesz się!" : "Do
zobaczenia!"));
Jak to działa?
Omawiając działanie operatora ternarnego, zarówno w wersji Java 1.4,
jak i Tiger, warto wspomnieć o pewnych dodatkowych szczegółach.
W wersjach poprzedzających wersję Tiger, [wyrażenie1] i [wyrażenie2]
musiały być tego samego typu lub musiała istnieć możliwość przypisa-
nia jednego drugiemu. Czyli na przykład oba wyrażenia musiały być ty-
pu String lub jedno typu int, a drugie typu float (ponieważ wartość
typu int może zostać przekształcona na typ float). W wersji Tiger
ograniczenia te są nieco luzniejsze ze względu na możliwość zastoso-
wania rozpakowywania. Jedno lub oba wyrażenia mogą zostać rozpa-
kowane, i dlatego jedno może być na przykład typu Integer, a drugie
typu Float. W tym przypadku rozpakowane zostaną oba wyrażenia,
a powstała wartość typu int zostanie rozszerzona do typu float. Wyni-
96 Rozdział 4: Automatyczne opakowywanie i rozpakowywanie
kiem wyrażenia będzie więc wartość typu float, która nie zostanie
z powrotem opakowana w typ Float.
Kolejną dodatkową właściwością wprowadzoną w wersji Tiger jest au-
tomatyczne rzutowanie referencji na ich wspólny typ. Wyjaśnia to po-
niższy przykład:
String s = "pewien";
Przykład ten
StringBuffer sb = new StringBuffer("tekst");
pochodzi z piątego
boolean mutable = true;
wydania książki
Java in a Nutshell
CharSequence cs = mutable ? sb : s;
(O Reilly).
W wersjach poprzedzających wersję Tiger podczas kompilacji tego kodu
wystąpił by błąd, ponieważ sb (typu StringBuffer) i s (typu String) nie
mogą być do siebie przypisywane. Ponieważ oba typy implementują in-
terfejs CharSequence, kod ten uda się jednak skompilować, jeśli zastosu-
jemy rzutowanie:
CharSequence cs = mutable ? (CharSequence)sb : (CharSequence)s;
W wersji Tiger można użyć dowolnego wspólnego typu dla obu wyra-
żeń. W tym przypadku CharSequence spełnia to wymaganie i może być
Z punktu widzenia
poprawnym typem wyniku wyrażenia.
technicznego
możliwość ta
Efektem takiego rozwiązania jest to, że każde dwa obiekty zawsze mają
związana jest
wspólny typ java.lang.Object, wobec czego wynik działania operatora
z obsługą
ternarnego na wyrażeniach, które nie są typów podstawowych, może generyczności
w wersji Tiger,
zostać przypisany do obiektu typu java.lang.Object.
ale wydaje mi się,
że lepiej było
wspomnieć o niej
Instrukcje sterujące i rozpakowywanie
w tym miejscu.
Generyczność
W języku Java istnieje kilka instrukcji sterujących, których argumentem została omówiona
szczegółowo
jest wartość typu boolean lub wyrażenie, którego wynik jest typu
w rozdziale 2.
boolean. Fakt, że w instrukcjach tych mogą teraz występować również
obiekty typu Boolean, nie powinien już stanowić zaskoczenia. Dodatkowo
instrukcja wyboru switch akceptuje szereg nowych typów.
Jak to osiągnąć?
Wprowadzona w wersji Tiger możliwość automatycznego rozpakowy-
wania obiektów typu Boolean do wartości typu boolean używana jest
Instrukcje sterujące i rozpakowywanie 97
także w przypadku instrukcji if/else, while i do. Poniższy przykład nie
wymaga szczegółowych objaśnień:
Boolean arriving = false;
Boolean late = true;
Integer peopleInRoom = 0;
int maxCapacity = 100;
boolean timeToLeave = false;
while (peopleInRoom < maxCapacity) {
if (arriving) {
System.out.println("Miło Cię widzieć.");
peopleInRoom++;
} else {
Uruchamiając
peopleInRoom--;
ten przykład,
}
należy pamiętać,
if (timeToLeave) {
że wykonuje on
do {
System.out.printf("Osoba numer %d musi opuścić pokój!%n",
nieskończoną pętlę.
peopleInRoom);
peopleInRoom--;
} while (peopleInRoom > 0);
}
}
W przykładzie tym zachodzi wiele operacji opakowywania i rozpako-
wywania w różnych instrukcjach sterujących. Warto dokładnie przeana-
lizować ich działanie.
Inną instrukcją, która zyskała na wprowadzeniu automatycznego rozpa-
kowywania, jest instrukcja wyboru switch. We wcześniejszych wer-
sjach języka Java akceptowała ona jedynie wartości typów int, short,
char i byte. Oprócz typów wyliczeniowych wprowadzonych w wersji Ti-
Typy wyliczeniowe
ger obsługuje ona dzięki rozpakowywaniu teraz również obiekty typów
omówiłem
Integer, Short, Char i Byte.
w rozdziale 3.
Wybór metody przeciążonej
Opakowywanie i rozpakowywanie stanowią rozwiązanie wielu typowych
problemów (lub przynajmniej czynią życie programisty wygodniej-
szym). Równocześnie jednak same mogą wprowadzać pewne problemy,
zwłaszcza w obszarze wyboru metody. Wybór metody jest procesem,
w którym kompilator języka Java ustala metodę, jaką należy wywołać.
Należy pamiętać, że opakowywanie i rozpakowywanie mają wpływ na
przebieg tego procesu.
98 Rozdział 4: Automatyczne opakowywanie i rozpakowywanie
Jak to osiągnąć?
W zwykłej sytuacji wybór metody w języku Java odbywa się na podsta-
wie nazwy metody. Jednak w przypadku, gdy nazwa metody jest prze-
ciążona, konieczne staje się wykonanie dodatkowego kroku. Wersja
przeciążonej metody wybierana jest na podstawie dopasowania listy ar-
gumentów. Jeśli dopasowanie to się nie uda, kompilator zgłosi błąd.
Brzmi prosto, prawda? Wezmy pod uwagę poniższe dwie metody:
public void doSomething(double num);
public void doSomething(Integer num);
Załóżmy teraz, że metodę doSomething() wywołaliśmy w następujący
sposób:
int foo = 1;
doSomething(foo);
Która metoda zostanie wywołana? We wcześniejszych wersjach języka
Java jej ustalenie nie sprawi nam kłopotu. Wartość typu int zostanie
rozszerzona do typu double i wywołana zostanie metoda doSomething
(double num). Jednak w wersji Tiger wydaje się, że nastąpi opakowa-
nie wartości typu int i wywołana zostanie metoda doSomething(int
num). Chociaż taki sposób działania wydaje się sensowny, jednak tak się
nie stanie.
Wyobrazmy sobie sytuację, w której napisalibyśmy powyższy program,
skompilowali go i przetestowali w języku Java 1.4, a następnie w wersji
Tiger. Okazałoby się, że działa on różnie w zależności od wersji języka.
Dlatego też obowiązuje zasada, że w wersji Tiger zawsze zostanie wy-
brana ta sama metoda, która zostałaby wybrana w wersji 1.4. W prak-
tyce powinniśmy unikać takiego korzystania z przeciążania jak w po-
wyższym przykładzie. Jeśli będziemy dokładnie specyfikować listy
argumentów metod, problem ten przestanie istnieć.
Jak to działa?
Ze względu na wspomnianą zasadę w wersji Tiger wybór metody odby-
wa się w trzech etapach:
Wybór metody przeciążonej 99
1. Kompilator próbuje określić właściwą metodę bez stosowania opera-
Listy argumentów
o zmiennej długości
cji opakowywania i rozpakowywania, a także zmiennych list argu-
omówione zostaną
mentów. Na skutek wykonania tego etapu wybranie zostania taka
w rozdziale 5.
sama metoda jak w przypadku Java 1.4.
2. Jeśli pierwszy etap zawiedzie, kompilator próbuje ponownie znalezć
odpowiednią metodę, ale tym razem stosując opakowywanie i roz-
pakowywanie. Metody mające listy argumentów o zmiennej długości
na tym etapie nie są brane pod uwagę.
3. Jeśli zawiedzie również drugi etap, kompilator podejmuje ostatnią
próbę, uwzględniając opakowywanie i rozpakowywanie, a także listy
argumentów o zmiennej długości.
Zastosowanie powyższych zasad zapewnia spójność działania ze wcze-
śniejszymi wersjami języka Java.
100 Rozdział 4: Automatyczne opakowywanie i rozpakowywanie


Wyszukiwarka

Podobne podstrony:
Visual Basic 2005 Zapiski programisty
java Tworzenie i obsługa programów
Excel 2003 Programowanie Zapiski programisty
Spring Zapiski programisty
Perl Testowanie Zapiski programisty
JAVA 03 konstrukcja programu
Efektywne Programowanie W Języku Java
Java Zadania z programowania z przykładowymi rozwiązaniami
Java?ektywne programowanie Wydanie II javep2

więcej podobnych podstron