You are on page 1of 89

IDZ DO

PRZYKADOWY ROZDZIA
SPIS TRECI

KATALOG KSIEK
KATALOG ONLINE

Java. Programowanie
obiektowe
Autor: Marek Wierzbicki
ISBN: 83-246-0290-9
Format: B5, stron: 264

ZAMW DRUKOWANY KATALOG

TWJ KOSZYK
DODAJ DO KOSZYKA

CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK

CZYTELNIA
FRAGMENTY KSIEK ONLINE

Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl

Doskonae wprowadzenie w wiat obiektowoci


Podstawowe zasady programowania obiektowego
Programowanie sterowane zdarzeniami
Obsuga wyjtkw i wielowtkowoci
Programowanie obiektowe to technologia, ktra zdobya ju bardzo mocn pozycj
wrd twrcw oprogramowania. Nadal jednak wielu programistw, ktrzy zdobywali
dowiadczenie, uywajc jzykw proceduralnych, ma problemy z jej zrozumieniem
i wszechstronnym stosowaniem. Wiele jzykw programowania okrelanych mianem
obiektowe wywodzi si z jzykw proceduralnych, co ogranicza moliwoci
wykorzystywania wszystkich zalet obiektowoci. Ogranicze tych pozbawiona jest
Java stworzony od podstaw, nowoczesny, bezpieczny, niezaleny od typu komputera
i systemu operacyjnego, w peni obiektowy jzyk programowania.
Ksika Java. Programowanie obiektowe opisuje wszystkie aspekty programowania
obiektowego w Javie. Pocztkujcy uytkownicy tego jzyka znajd w niej wyjanienia
nawet najbardziej skomplikowanych mechanizmw obiektowoci, a ci, ktrzy posiadaj
ju pewne dowiadczenie, mog wykorzysta j w charakterze podrcznego
kompendium wiedzy. Mona znale w niej omwienie zarwno podstawowych
zagadnie, jak i zaawansowanych technik obsugi bdw, programowania
wielowtkowego i sterowanego zdarzeniami. W ksice przedstawiono rwnie metody
tworzenia wydajnie dziaajcych programw, ktre do uruchomienia nie wymagaj
maszyn o potnej mocy obliczeniowej.
Cechy programowania obiektowego
Obiektowo w Javie
Tworzenie i stosowanie klas i obiektw
Budowanie pakietw
Tworzenie apletw
Komunikacja apletw ze skryptami Java Script
Obiekty nasuchujce i obsuga zdarze
Przechwytywanie wyjtkw
Synchronizacja wtkw
Poznaj moliwoci technologii obiektowej w praktyce

Od autora ......................................................................................... 7
Rozdzia 1. Wprowadzenie ................................................................................ 11
1.1. Oglne cechy programowania obiektowego ...........................................................12
1.1.1. Hermetyzacja ................................................................................................13
1.1.2. Dziedziczenie cech ........................................................................................14
1.1.3. Dziedziczenie metod i polimorfizm ..............................................................16
1.1.4. Nowa jako dziaania ..................................................................................17
1.2. Cechy szczeglne obiektowoci Javy ......................................................................18
1.2.1. Obiekty w Javie .............................................................................................21
1.2.2. Deklaracje dostpnoci .................................................................................22
1.2.3. Klasy wewntrzne i zewntrzne ....................................................................22
1.2.4. Klasy abstrakcyjne ........................................................................................23
1.2.5. Interfejsy .......................................................................................................24
1.2.6. Implementacje ...............................................................................................25
1.2.7. Klasy finalne .................................................................................................25
1.2.8. Metody i klasy statyczne ...............................................................................26
1.2.9. Klasy anonimowe ..........................................................................................27
1.2.10. Obiekty refleksyjne .......................................................................................28
1.2.11. Zdalne wykonywanie metod .........................................................................28
1.2.12. Pakiety ..........................................................................................................29
1.2.13. Zarzdzanie pamici ...................................................................................30
1.2.14. Konwersja typw ..........................................................................................30
1.3. Podsumowanie .........................................................................................................31

Rozdzia 2. Klasy i obiekty w Javie .................................................................... 33


2.1. Klasy ........................................................................................................................33
2.1.1. Tworzenie klas ..............................................................................................33
2.1.2. Pola ................................................................................................................35
2.1.3. Metody ..........................................................................................................35
2.1.4. Hermetyzacja i modyfikator private .............................................................36
2.1.5. Przecianie metod .......................................................................................37
2.1.6. Sowo kluczowe this .....................................................................................38
2.1.7. Konstruktor ...................................................................................................39
2.1.8. Przecianie konstruktorw ..........................................................................40
2.1.9. Dziedziczenie ................................................................................................43
2.1.10. Inicjator klasy i obiektu ................................................................................44
2.1.11. Kolejno inicjacji klas .................................................................................47
2.1.12. Destruktor .....................................................................................................50

Java. Programowanie obiektowe


2.1.13. Przykrywanie metod .....................................................................................51
2.1.14. Odwoanie do klas nadrzdnych ...................................................................52
2.1.15. Odwoanie do pl klas nadrzdnych .............................................................53
2.1.16. Klasy abstrakcyjne ........................................................................................54
2.2. Obiekty ....................................................................................................................55
2.2.1. Rozwaania o adresie ....................................................................................55
2.2.2. Jawne uycie obiektw .................................................................................56
2.2.3. Kopiowanie obiektw ...................................................................................58
2.2.4. Niejawne uywanie obiektw .......................................................................59
2.2.5. Typ zmiennej i obiektu. Operator instanceof ................................................60
2.2.6. Efekty polimorfizmu .....................................................................................62
2.3. Klasy wewntrzne i lokalne ....................................................................................63
2.3.1. Dostp do zmiennych klasy zawierajcej .....................................................65
2.3.2. Polimorfizm i zmienne klasy zawierajcej ...................................................66
2.3.3. Zmienne lokalne w klasie lokalnej ................................................................68
2.3.4. this w klasach wewntrznych ........................................................................69
2.3.5. Korzystanie z klas wewntrznych .................................................................71
2.4. Interfejsy ..................................................................................................................73
2.4.1. Definicja interfejsu ........................................................................................74
2.4.2. Implementacje ...............................................................................................74
2.4.3. Zastosowanie interfejsw ..............................................................................76
2.4.4. Stae symboliczne .........................................................................................77
2.4.5. Troch kodu w interfejsie .............................................................................79
2.4.6. Dziedziczenie interfejsw .............................................................................81
2.4.7. Egzemplarz interfejsu ...................................................................................83
2.5. Klasy anonimowe ....................................................................................................84
2.5.1. Klasyczne uycie klasy anonimowej ............................................................85
2.5.2. Jawna klasa anonimowa ................................................................................87
2.5.3. Konstruktor klasy anonimowej .....................................................................88
2.6. Obiekty refleksyjne .................................................................................................89
2.6.1. Obiekt tworzony refleksyjnie ........................................................................89
2.6.2. Oglne rozpoznawanie klasy ........................................................................91
2.6.3. Przykad uycia refleksji ...............................................................................92
2.6.4. Zwizek refleksji z obiektowoci ................................................................94
2.7. Metody .....................................................................................................................95
2.7.1. Zwracanie wartoci przez metod .................................................................95
2.7.2. Przekazywanie parametrw przez warto ...................................................96
2.7.3. Zmiana wartoci parametru ...........................................................................97
2.7.4. Metody ze zmienn liczb parametrw ........................................................99
2.7.5. Zakres nazw zmiennych ..............................................................................100
2.8. Pakiety ...................................................................................................................101
2.8.1. Tworzenie pakietw ....................................................................................101
2.8.2. Uywanie pakietw .....................................................................................103
2.8.3. Lista pakietw .............................................................................................104
2.9. Modyfikatory .........................................................................................................105
2.9.1. Modyfikatory dostpu .................................................................................106
2.9.2. Pokrywanie modyfikatorw dostpu ..........................................................107
2.9.3. Metody i pola statyczne ..............................................................................109
2.9.4. Pola finalne .................................................................................................111
2.9.5. Metody i klasy finalne .................................................................................112
2.9.6. Pola podlegajce zmianie ............................................................................113
2.9.7. Metody synchronizowane ...........................................................................113
2.9.8. Pola ulotne ...................................................................................................114
2.9.9. Metody rodzime ..........................................................................................114
2.10. Podsumowanie ......................................................................................................115

Spis treci

Rozdzia 3. Aplet jako obiekt na stronie HTML ................................................ 117


3.1. Program na stronie internetowej ............................................................................118
3.1.1. Aplet jako program .....................................................................................118
3.1.2. Osadzenie obiektu na stronie ......................................................................119
3.1.3. Wersja Javy w przegldarce ........................................................................122
3.2. Predefiniowane skadowe apletu ...........................................................................123
3.2.1. Inicjacja apletu ............................................................................................124
3.2.2. Wstrzymanie i wznowienie pracy ...............................................................125
3.2.3. Zamykanie okna przegldarki .....................................................................125
3.2.4. Wygld i jego odwieanie .........................................................................126
3.3. Komunikacja ze wiatem zewntrznym ................................................................130
3.3.1. Wyprowadzanie informacji tekstowych ......................................................130
3.3.2. Okienko dialogowe .....................................................................................132
3.3.3. Pobieranie parametrw z pliku HTML .......................................................135
3.3.4. Pobieranie i odtwarzanie plikw z serwera .................................................136
3.3.5. Komunikacja midzy apletami ....................................................................137
3.3.6. Pobieranie informacji z linii adresu ............................................................140
3.4. Aplet a JavaScript ..................................................................................................142
3.4.1. Wywoanie funkcji JavaScript z apletu .......................................................143
3.4.2. Bezporednie uycie JavaScriptu ................................................................145
3.4.3. Obsuga rejestru przegldarki .....................................................................146
3.4.4. Wywoanie Javy z JavaScriptu ...................................................................148
3.5. Aplet jako samodzielna aplikacja ..........................................................................150
3.6. Ograniczenia w apletach .......................................................................................151
3.7. Podsumowanie .......................................................................................................152

Rozdzia 4. Programowanie sterowane zdarzeniami .......................................... 153


4.1. Zarys nowej idei ....................................................................................................154
4.2. Klasyczna obsuga zdarze ...................................................................................155
4.2.1. Usuwanie klas anonimowych ......................................................................158
4.2.2. Obsuga zdarze poza klas ........................................................................161
4.3. Wspdzielenie obiektw nasuchujcych .............................................................163
4.4. Zdarzenia standardowe ..........................................................................................165
4.4.1. Zdarzenie action ..........................................................................................166
4.4.2. Zdarzenie item .............................................................................................169
4.4.3. Zdarzenie adjustment ..................................................................................170
4.4.4. Zdarzenie text ..............................................................................................171
4.4.5. Zdarzenia window .......................................................................................171
4.4.6. Zdarzenia component ..................................................................................172
4.4.7. Zdarzenia mouse .........................................................................................173
4.4.8. Zdarzenia mouseMotion .............................................................................174
4.4.9. Zdarzenia key ..............................................................................................176
4.4.10. Zdarzenia focus ...........................................................................................178
4.4.11. Zdarzenia container ....................................................................................180
4.4.12. Usuwanie obiektw nasuchujcych ...........................................................180
4.4.13. Powizanie obiektw ze zdarzeniami .........................................................181
4.5. Zdarzenia z parametrem ........................................................................................183
4.5.1 Identyfikacja miejsca pochodzenia komunikatu ..........................................183
4.5.2. Wyniesienie wasnych parametrw poza klas ...........................................186
4.6. acuchy zdarze ..................................................................................................188
4.7. Listener kontra Adapter .........................................................................................189
4.8. Obsuga w klasie pochodnej ..................................................................................190
4.8.1. Obsuga zdarze w klasie ............................................................................190
4.8.2. Obiekt z wewntrzn obsug .....................................................................191

Java. Programowanie obiektowe


4.8.3. Rzadko stosowana metoda ..........................................................................192
4.8.4. Powizanie klas i zdarze ...........................................................................193
4.8.5. Wady i zalety wewntrznej obsugi ............................................................194
4.9. Zaszoci w obsudze zdarze ...............................................................................195
4.10. Podsumowanie ......................................................................................................196

Rozdzia 5. Obsuga wyjtkw ......................................................................... 197


5.1. Obsuga wyjtkw przez program .........................................................................198
5.1.1. Wyjtek jako obiekt ....................................................................................198
5.1.2. Konstrukcja podstawowa try catch ..........................................................202
5.1.3. Przechwytywanie rnych wyjtkw ..........................................................203
5.1.4. Zagniedanie obsugi wyjtkw ................................................................204
5.1.5. Sowo kluczowe finally ...............................................................................206
5.1.6. Obsuga wyjtkw poza metod .................................................................208
5.1.7. Programowe generowanie wyjtkw ..........................................................210
5.1.8. Wielokrotna obsuga tego samego wyjtku ................................................210
5.2. Wasne typy wyjtkw ..........................................................................................212
5.3. Obsuga wyjtkw przez JVM ..............................................................................214
5.4. Podsumowanie .......................................................................................................217

Rozdzia 6. Programowanie wielowtkowe ...................................................... 219


6.1. Techniczna strona wielowtkowoci .....................................................................220
6.2. Podstawy realizacji wtkw ..................................................................................222
6.2.1. Obiekty zarzdzajce wtkami ....................................................................222
6.2.2. Obiekty-wtki ..............................................................................................223
6.3. Tworzenie klas wtkw .........................................................................................223
6.4. Zarzdzanie wtkami .............................................................................................225
6.4.1. Uruchomienie i zatrzymanie wtku ............................................................225
6.4.2. Wstrzymanie pracy wtku ...........................................................................226
6.4.3. Wtki a dziaalno gwna ........................................................................227
6.4.4. Zawieszenie pracy wtku ............................................................................228
6.4.5. Inteligentne wstrzymanie pracy ..................................................................229
6.4.6. Wymuszenie przeczenia wtku ................................................................231
6.4.7. Priorytety wtkw .......................................................................................233
6.5. Synchronizacja wtkw .........................................................................................236
6.5.1. Praca synchroniczna ....................................................................................236
6.5.2. Przyczyny synchronizacji metod ................................................................237
6.5.3. Metody rnego typu ..................................................................................240
6.5.4. Synchronizacja metod asynchronicznych ...................................................242
6.5.5. Wzajemna blokada ......................................................................................242
6.5.6. Przerywanie metod synchronizowanych .....................................................244
6.6. Podsumowanie .......................................................................................................246

Sowo kocowe ............................................................................ 247


Literatura ..................................................................................... 249
Skorowidz ..................................................................................... 251

Rozdzia 2.

Poprzedni rozdzia wprowadza oglnie pojt ide programowania obiektowego oraz


jej modyfikacje na potrzeby Javy. W tym rozdziale zajm si tym samym problemem,
ale tutaj poka rodki realizacji idei opisanych wczeniej. Bdziesz mg dowiedzie
si, jak w praktyce realizuje si programowanie obiektowe z uyciem kodu rdowego
w Javie. Poszczeglne konstrukcje jzyka s omwione z perspektywy kodowania
oraz dziaania wirtualnej maszyny Javy, czyli JVM (Java Virtual Machine). Pomijam
wikszo rozwaa teoretycznych nad cechami poszczeglnych konstrukcji, ktre
opisaem wczeniej, dlatego licz, e w dostateczny sposb zapoznae si z treci
poprzedniego rozdziau.

2.1. Klasy
Klasy okrelaj posta, struktur i dziaanie obiektw, ktre s egzemplarzami klas.
W zwizku z zastosowaniem w Javie skrajnie ortodoksyjnego podejcia program napisany z uyciem tego jzyka musi mie, poza kilkoma wyjtkami (czyli prostymi
podstawowymi typami danych), struktur oraz dziaanie lub algorytm, ktry wykonuje, zaprojektowane z uyciem klas (a zrealizowane z uyciem ich egzemplarzy,
czyli obiektw).

2.1.1. Tworzenie klas


Najprostsza moliwa do stworzenia klasa ma posta:
class Simple {}

Charakteryzuje j sowo kluczowe class, nazwa klasy (w tym wypadku Simple) oraz
para nawiasw klamrowych, ktre reprezentuj jej ciao (w tym przypadku s puste).
Klasa ta musi by umieszczona w pliku Simple.java. Tak utworzony plik moe zosta
poddany poprawnej kompilacji i stanowi zupenie poprawn (cho cakiem nieprzydatn)
klas Javy. Naley pamita, e kada klasa publiczna musi by zapisana w osobnym
pliku, ktrego nazwa musi by dokadnie taka sama (oczywicie plus rozszerzenie

34

Java. Programowanie obiektowe

.java) jak nazwa klasy zdefiniowanej wewntrz (wcznie z rozrnieniem na due i mae
litery). Teoria mwi, e nazwy klas mog zawiera tak zwane znaki narodowe, ale ze
wzgldu na rne standardy kodowania (nawet w obrbie jednego systemu operacyjnego) nie powinno si stosowa liter innych ni aciskie.
Definicja klasy podstawowej musi by tworzona wedug szablonu zaprezentowanego
na listingu 2.1 (elementy ujte w nawiasy kwadratowe s opcjonalne i nie musz wystpowa).
Listing 2.1. Szablon definicji klasy
[modyfikator] class NazwaKlasy {
[modyfikator] typ nazwa_pola_1;
...
[modyfikator] typ nazwa_pola_k;

[modyfikator] typ nazwa_metody_1([lista_parametrw])


{
ciao_metody_1
}
...
[modyfikator] typ nazwa_metody_L([lista_parametrw])
{
ciao_metody_L
}

Klasa moe posiada dowoln liczb pl i metod (w tym zero, nawet cznie dla pl
i metod, jak pokazaem to wczeniej w najprostszej klasie Simple).
Poniej umieszczam objanienie poszczeglnych elementw zaprezentowanych w szablonie na listingu 2.1.
t class sowo kluczowe okrelajce definicj klasy.
t NazwaKlasy identyfikator okrelajcy nazw klasy.
t modyfikator sowo lub sowa kluczowe oddzielone od siebie spacj

okrelajce sposb traktowania elementu, do ktrego si odnosz. Modyfikator


moe te oznacza ograniczenie lub rozszerzenie dostpu do elementu. Pene
wyjanienie znaczenia tego elementu jzyka znajduje si w podrozdziale 2.9.
Modyfikatory.

t typ typ pola lub metody moe to by typ prosty (byte, short, int, long,
char, float, double lub boolean oraz void tylko w odniesieniu do metody),

klasa bd tablica (array) elementw jednego typu.


t nazwa_pola_x identyfikator jednoznacznie okrelajcy pole konstruowanej klasy.
t nazwa_metody_x identyfikator, ktry wraz z list parametrw jednoznacznie

okreli metod.

t lista_parametrw lista par rozdzielonych przecinkami skadajcych si

z okrelenia typu i nazwy egzemplarza danego typu. Jeli nie zamierzamy


przekaza do metody adnych parametrw, jej deklaracja powinna zawiera

Rozdzia 2. Klasy i obiekty w Javie

35

par pustych nawiasw. Zwracam tu uwag na odstpstwa od C++, ktre


w takim przypadku powinno (zamiast pustych nawiasw) zawiera sowo
void, oraz rnice w stosunku do Object Pascala niezawierajcego w takim
przypadku nawiasw.
t ciaco_metody_x zbir instrukcji jzyka Java okrelajcy funkcjonalno

danej metody.

2.1.2. Pola
Pola s to miejsca, w ktrych przechowywane s informacje charakterystyczne dla
caej klasy bd dla jej konkretnego egzemplarza. O polach mwi si te czasami, e
s to egzemplarze zmiennych nalece do konkretnego egzemplarza klasy. W praktyce moemy traktowa pola jako lokalne zmienne danej klasy z zastrzeeniem, e zakres ich widzialnoci i zachowania jest okrelony przez modyfikatory poszczeglnych
pl. Klasyczna deklaracja pola odbywa si wedug schematu:
[modyfikator] typ nazwa_pola_k;

Przykad klasy zawierajcej tylko dwa pola pokazany jest na listingu 2.2.
Listing 2.2. Klasa posiadajca tylko dwa pola
class Point {
int x; // pooenie na osi 0X
int y; // pooenie na osi 0Y
}

W przykadzie tym pola s zmiennymi prostymi. Nie ma jednak adnych przeciwwskaza, eby byy zmiennymi zoonymi, w tym rwnie obiektami.

2.1.3. Metody
Inaczej ni inne jzyki obiektowe takie jak C++ czy Object Pascal, Java nie tylko
gromadzi wszystkie informacje w plikach jednego rodzaju (tekstowych, z rozszerzeniem .java), ale rwnie stara si je przechowywa w moliwie najbardziej skoncentrowany sposb. W C++ istniej pliki nagwkowe, ktre przechowuj struktur obiektw,
i waciwe pliki z programem przechowujce midzy innymi obiekty. W Object Pascalu
informacje te s co prawda zawarte w jednym pliku, jednak cz jest w sekcji interface, cz w implementation. W Javie wszystko jest w jednym miejscu. Caa informacja o metodzie zawarta jest tu przed jej ciaem, tak jak to wida na listingu 2.3.
Listing 2.3. Szablon definicji metody
[modyfikator] typ nazwa_metody([lista_parametrw])
{
// blok instrukcji
}

36

Java. Programowanie obiektowe

Jeli typ metody jest rny od void (czyli funkcja zwraca jak warto), powinna ona
by zakoczona wierszem:
return wyliczonaWartosc;

gdzie wyliczonaWartosc musi by takiego samego typu jak typ metody.


Po zaprezentowaniu schematu tworzenia klas mog przystpi do przedstawienia
przykadu prostej klasy, ktra umoliwia przechowywanie informacji o pooeniu
punktu na paszczynie wraz z metodami umoliwiajcymi okrelenie pooenia pocztkowego punktu i przemieszczenia go. Klasa ta pokazana jest na listingu 2.4.
Listing 2.4. Klasa opisujca punkt
class Point {
int x; // pooenie na osi 0X
int y; // pooenie na osi 0Y
// ustawienie nowej pozycji
public void newPosition(int newX, int newY) {
x = newX;
y = newY;
}
// przemieszczenie punktu
public void changePosition(int dX, int dY) {
x = x+dX;
y = y+dY;
}
}

W dalszej czci tego rozdziau bd rozszerza definicj tej klasy i precyzowa jej
znaczenie.

2.1.4. Hermetyzacja i modyfikator private


Wprowadzajc ide programowania obiektowego, zwracaem uwag na jej podstawow cech (i zarazem bardzo wan zalet), czyli hermetyzacj. Klasa (a wraz z ni
obiekt) miaa gromadzi w jednym miejscu dane i procedury ich obsugi. Jednak miao to
by zgromadzone w taki sposb, aby osoba uywajca obiektu miaa jak najmniejszy
dostp do danych (tylko do tych niezbdnych). Miao to zapewni zarwno zmniejszenie liczby bdw popenianych w czasie kodowania, jak i podniesienie przejrzystoci programu. Przedstawiona wczeniej klasa Point nie stanowia idealnej reprezentacji hermetycznej klasy, gdy udostpniaa na zewntrz wszystkie, a nie tylko
niezbdne elementy. Aby uniemoliwi dostp do pl, ktre w idei klasy nie musz
by dostpne z zewntrz, naley je oznaczy modyfikatorem private. Na listingu 2.5
przedstawiam poprawion, bardziej hermetyczn wersj klasy Point.
Listing 2.5. Poprawiona klasa opisujca punkt
class Point {
private int x; // pooenie na osi 0X
private int y; // pooenie na osi 0Y

Rozdzia 2. Klasy i obiekty w Javie

37

// odczyt wartoci
public int get p b
return x;
}
public int getY p b
return y;
}
// ustawienie nowej pozycji
public void newPosition(int newX, int newY) {
x = newX;
y = newY;
}
// przemieszczenie punktu
public void changePosition(int dX, int dY) {
x = x+dX;
y = y+dY;
}

Na listingu 2.5 wytuciem rnice w stosunku do wczeniejszej wersji klasy, czyli


ukrycie bezporednich wartoci x i y oraz udostpnienie w zamian ich wartoci przez
metody getX i getY. Zaleta takiego rozwizania jest widoczna. Nie mona, nawet
przez przypadek, odwoa si bezporednio do x i y, dziki czemu nie moe nastpi
przypadkowa ich modyfikacja. Aby je odczyta, trzeba jawnie wywoa getX lub getY.
Aby je ustawi, trzeba jawnie wywoa newPosition (mona te utworzy metody setX
i setY, aby ustawia te parametry pojedynczo). Dopiero tak skonstruowana klasa
spenia warunki hermetyzacji.

2.1.5. Przecianie metod


Istniej sytuacje, w ktrych niektrzy programici uwaaj, e wskazane jest, aby
mona byo utworzy kilka metod o tych samych nazwach, lecz o rnym zestawie
parametrw. Jako przykad mona pokaza kolejne rozszerzenie naszej klasy Point
o now wersj metody newPosition. Rozszerzenie to pokazane jest na listingu 2.6.
Listing 2.6. Kolejna wersja klasy opisujcej punkt
class Point {
private int x;
private int y;

// pooenie na osi 0X
// pooenie na osi 0Y

// ustawienie nowej pozycji


public void newPosition(int newX, int newY) {
x = newX;
y = newY;
}
// ustawienie nowej pozycji na (0,0)
public void newPosition() {
x = 0;
y = 0;
}

// pozostae metody klasy Point


// ...

38

Java. Programowanie obiektowe

Pokazana na listingu 2.6 klasa ma dwie metody newPosition. Jedna, wywoana z parametrami, ustawia wsprzdne punktu na wartoci podane jako parametry. Druga,
bez parametrw, ustawia wsprzdne punktu na warto domyln (0,0). Mona prbowa wyobrazi sobie sytuacj, w ktrej nie da si zastosowa innego rozwizania.
Czsto jednak przecianie nie jest konieczne. Osobicie uwaam, e kiedy tylko nie
ma takiej potrzeby, nie powinno si go stosowa. Jednak w standardowych bibliotekach Javy wiele funkcji jest przecionych, co powoduje, e programici chtnie
trzymaj si takiego standardu kodowania. Na przykad w projektowanej przez nas
klasie zamiast przeciania metody newPosition mona by zastosowa dwie rne
metody newPosition oraz defaultPosition. Jeeli jednak decydujemy si na przecianie metod, powinnimy pamita o nastpujcych uwagach:
t Metody rozrniane s wycznie na podstawie liczby i typw przekazywanych

do nich parametrw. Wywoanie metody powinno odby si z waciwym


zestawem parametrw, gdy w przeciwnym wypadku kompilator zgosi bd.

t Metody nie s rozrniane na podstawie nazw parametrw formalnych,

w zwizku z tym prba stworzenia dwch metod o tym samym zestawie


typw parametrw i rnych ich nazwach zakoczy si bdem.

t Metody nie s rwnie rozrniane na podstawie typw zwracanej wartoci.

W zwizku z tym dwie metody o takim samym zestawie parametrw, lecz


o rnym typie zwracanego wyniku zostan potraktowane jak jedna metoda
i kompilator rwnie zgosi bd.

t Jak wszdzie, w Javie wielko liter ma znaczenie. W zwizku z tym istnienie


metod newPosition i NewPosition nie jest adnym przecieniem, gdy maj

one rne nazwy (wedug mnie stosowanie nazw rnicych si wycznie


wielkoci liter to bardzo zy pomys).

2.1.6. Sowo kluczowe this


Java zawiera w swojej skadni ciekawe, cho pozornie nieprzydatne sowo this. Z punktu
widzenia formalnego wszystkie odwoania do wasnych pl i metod s dokonywane
w stosunku do tej klasy, w ktrej si znajdujemy (czyli po angielsku wanie this).
Podobny mechanizm stosowany jest na przykad w Object Pascalu, ktry domylnie
zakada, e wszystkie nieprzekierowane odwoania wykonywane s w stosunku do
siebie (w Pascalu do przekierowa uywa si sowa Self). Przykad wczeniej uywanej metody newPosition moe by (a w zasadzie z punktu widzenia skrajnego formalizmu powinien by) zapisany w postaci zaprezentowanej na listingu 2.7.
Listing 2.7. Bardzo formalna definicja metody w klasie opisujcej punkt
public void newPosition(int newX, int newY) {
this.x = newX;
this.y = newY;
}

Oczywicie nikt tego nie robi, gdy poza niepotrzebnym nakadem pracy nie zyskuje
si w ten sposb adnego ciekawego efektu. Nie zawsze jednak stosowanie tego
przedrostka nie daje adnego efektu. Istniej sytuacje, kiedy kod rdowy programu

Rozdzia 2. Klasy i obiekty w Javie

39

bez sowa this nie determinuje poprawnie elementu, do ktrego zamierzalimy si


odwoa. Dzieje si tak wtedy, gdy parametry metody maj takie same nazwy jak
pola klasy. Na listingu 2.8 przedstawiam zmodyfikowan wersj metody newPosition,
w ktrej uycie sowa this jest ju jak najbardziej uzasadnione.
Listing 2.8. Uzasadnione uycie sowa this w klasie opisujcej punkt
public void newPosition(int x, int y) {
this.x = x;
this.y = y;
}

Patrick Naughton, jeden ze wsptwrcw Javy, uwaa, e taka konstrukcja upraszcza


tekst rdowy oraz czyni go bardziej przejrzystym i mniej podatnym na bdy. W zwizku
z tak tez stawian przez wspautora jzyka wiele osb nagminnie stosuje takie
konstrukcje. Wedug mnie jest to niepotrzebny manieryzm, ktry zaciemnia obraz sytuacji
i jest przyczyn duej liczby drobnych i zupenie niepotrzebnych bdw. Warto popatrze na hipotetyczn metod newPosition pokazan na listingu 2.9, ktra przelicza
przed ustawieniem warto pooenia z cali na centymetry, aby mona byo zobaczy,
e atwo jest si pomyli, stosujc te same nazwy dla parametrw i pl klasy.
Listing 2.9. Przykad popenienia bdu zasigu zmiennych
classFloatPoint {
float x, y;
public void newPosition(float x, float y) {
float xcm, ycm;
xcm = 2.51*x;
ycm = 2.51*y;
x = xcm; // zy zakres
y = ycm; // zy zakres
}
}

Oczywicie kompilator nie zgosi adnego bdu, gdy konstrukcja jest jak najbardziej poprawna, a my bdziemy si zastanawia, dlaczego pola obiektu nie s inicjowane we waciwy sposb. Ot w wierszach oznaczonych na listingu 2.9 komentarzem zy zakres podstawiamy wartoci do zmiennych, ktre posuyy nam do
przekazania wartoci do metody, a ktre nie s widoczne na zewntrz od niej (przykryy nazwy pl).
Rozszerzenie uycia sowa this pokazaem w paragrafach 2.1.8. Przecienie konstruktorw, 2.4.3. Zastosowanie interfejsw oraz 2.3.4. this w klasach wewntrznych.

2.1.7. Konstruktor
Mimo i zaprezentowana klasa Point jest w peni funkcjonalna w zakresie, jakiego od
niej oczekujemy, w praktyce brakuje jej elementu, ktry znacznie uatwiby jej (i kadej innej klasy) wykorzystanie. Ot bezporednio po utworzeniu obiektu, czyli egzemplarza tej klasy (co przedstawi w dalszej czci tego rozdziau), pooenie nowego

40

Java. Programowanie obiektowe

punktu jest nieokrelone. Dopiero po uyciu metody newPosition, ktra jawnie deklaruje nowe pooenie punktu, przestaje ono by nieokrelone, a zaczyna by takie, jak
to zostao w niej ustawione. W zwizku z tym po kadorazowym utworzeniu takiego
obiektu naleaoby pamita o zainicjowaniu jego pooenia. Znacznie wygodniej
byoby, gdyby inicjacja pooenia punktu odbywaa si automatycznie w czasie tworzenia obiektu. Jest to moliwe, pod warunkiem e skorzystamy z moliwoci stosowania specjalnej metody zwanej konstruktorem, wywoywanej automatycznie w czasie tworzenia egzemplarza klasy. Od zwykej metody odrniaj konstruktor dwie
kwestie nazwa zgodna z nazw klasy oraz brak typu. W stosunku do konstruktora
mona stosowa deklaracje zasigu, przy czym dobra praktyka sugeruje, aby zasig
widzialnoci konstruktora by dokadnie taki sam jak samej klasy. Byoby to bowiem
duym bdem, gdyby klasa bya widziana, a jej konstruktor nie. Przykadowy konstruktor dla klasy Point pokazywanej wczeniej bdzie mia posta zaprezentowan
na listingu 2.10.
Listing 2.10. Konstruktor klasy opisujcej punkt
// konstruktor klasy Point
Point(int newX, int newY) {
x = newX;
y = newY;
}

Brak typu w deklaracji konstruktora wynika z tego, e w praktyce zwraca on warto


typu dokadnie takiego samego jak klasa, w ktrej jest umieszczony, czyli domylnie
jego typ jest dokadnie taki jak nazwa klasy. Gdyby wic twrcy Javy chcieli by bardzo
pedantyczni, deklaracja konstruktora powinna wyglda jak na listingu 2.11.
Listing 2.11. Hipotetyczna deklaracja konstruktora
// teoretyczna deklaracja konstruktora
// (uwaga: bdna formalnie)
Point Point(int newX, int newY) {
x = newX;
y = newY;
}

Na szczcie nie ma potrzeby, aby tak utrudnia sobie ycie.

2.1.8. Przecianie konstruktorw


O ile przecienia metod mona unikn, stosujc rne nazwy metod (na przykad
dodajc rne przyrostki), o tyle przecienie konstruktorw moe okaza si niezbdne. Konstruktor to specyficzna, wywoywana w czasie tworzenia obiektu metoda
o nazwie zgodnej z nazw klasy. Ograniczenie takie (niewystpujce na przykad
w Object Pascalu, gdzie konstruktor moe mie dowoln nazw) wymusza stosowanie
przecienia konstruktorw, jeli chcemy korzysta z nich w sposb bardziej uniwersalny. Jako przykad wemy pokazywan wczeniej klas Point. Sugeruj dodanie do
niej drugiego konstruktora bez parametrw, ktry bdzie ustawia pooenie punktu
na pocztku ukadu wsprzdnych (0,0), tak jak na listingu 2.12.

Rozdzia 2. Klasy i obiekty w Javie

41

Listing 2.12. Deklaracja dwch konstruktorw o tej samej nazwie


class Point {
private int x; // pooenie na osi 0X
private int y; // pooenie na osi 0Y
// pierwszy konstruktor klasy Point
Point() {
x = 0;
y = 0;
}
// drugi konstruktor klasy Point
Point(int newX, int newY) {
x = newX;
y = newY;
}
//...
}

W tym przypadku nie jest moliwe ominicie przecienia ze wzgldu na konieczno zastosowania dla obu konstruktorw tej samej nazwy (czyli Point).
Udogodnienie wprowadzone przez mechanizm przeciania metod wprowadza bocznymi drzwiami moliwo zastosowania metod nazywajcych si tak samo jak klasy.
Na pierwszy rzut oka wydaje si, e bdziemy mieli do czynienia z konstruktorem,
cho w rzeczywistoci bdzie to zwyka metoda o nazwie takiej jak klasa. W szczeglnym przypadku moemy wic zastosowa konstrukcj pokazan na listingu 2.13.
Listing 2.13. Deklaracja metody i klasy o tej samej nazwie
class Klasa {
Klasa(){ /* konstruktor Klasa*/ }
// metoda o nazwie Klasa:
public int Klasa(int i) { return i; }
}

Uycie konstruktora i metody (troch wybiegam tu w przyszo, lecz mam nadziej,


e mi to wybaczysz) bdzie miao posta jak na listingu 2.14.
Listing 2.14. Uycie konstruktora i metody o tej samej nazwie
// wykorzystanie konstruktora
Klasa k = new Klasa();
// wykorzystanie metody
int i = k.Klasa(11);

Jakkolwiek taka konstrukcja jest moliwa, nie polecam jej ze wzgldu na wysok podatno na generowanie bdw w tym miejscu. Jeli uyjemy kompilatora z opcj
pedantycznej kompilacji (na przykad JIKES), w czasie przetwarzania tej konstrukcji
zgosi on co do niej zastrzeenie, lecz wykona proces kompilowania. Oto przykad
bdnego uycia zaprezentowanej klasy:
Klasa k = new Klasa(11);

42

Java. Programowanie obiektowe

Na pierwszy rzut oka wydaje si, e wszystko jest w porzdku. Odwoanie takie nie
skutkuje jednak wywoaniem konstruktora, tylko metody. Dlatego jak wczeniej napisaem, nie powinno si stosowa tej konstrukcji, chyba e szczeglne zaley nam na
zaciemnieniu struktury programu (na przykad w celu utrudnienia dekompilacji).
Warto zauway, e stosowanie konstruktora i metody o tej samej nazwie jest pewn
niecisoci w stosunku do kwestii przeciania metod. Zwyke metody nie s rozrniane na podstawie typu zwracanego wyniku. Natomiast konstruktor i metoda o tej
samej nazwie i tym samym zestawie parametrw s dla kompilatora rne. Dziki
temu moliwe jest totalne zaciemnienie kodu klasy, jak to pokazaem na listingu 2.15.
Listing 2.15. Metoda udajca domylny konstruktor
class Klasa {
public int Klasa() {
return 1;
}
}

Pokazana na listingu 2.15 metoda umoliwia napisanie fragmentu programu zaprezentowanego na listingu 2.16.
Listing 2.16. Uycie konstruktora i metody o takiej samej licie parametrw
// domylny, bezparametrowy konstruktor
Klasa k = new Klasa();
// metoda zwracajca wynik typu int
int i = k. Klasa();

Jakkolwiek s osoby, ktre lubuj si w stosowaniu takich konstrukcji, twierdzc e


jest to esencja programowania obiektowego, ja uwaam to za ze rozwizanie.
Na marginesie przecienia konstruktorw mona pokaza uycie sowa kluczowego
this w formie innej, ni pokazano w paragrafie 2.1.6. Sowo kluczowe this. Ot
odwoanie do samego tego sowa jest rwnowane odwoaniu do konstruktora klasy,
w ktrej si znajdujemy. Oczywicie ma to sens jedynie w przypadku, gdy klasa ma
kilka przecionych konstruktorw i jeden z nich, zamiast jawnie wykonywa jaki
blok instrukcji, odwouje si do innego. Na listingu 2.17 przedstawiam ten sam fragment klasy Point, jednak z uyciem wywoania jednego z konstruktorw przez drugi
za pomoc sowa this.
Listing 2.17. Uycie sowa this zamiast konstruktora
class Point {
private int x; // pooenie na osi 0X
private int y; // pooenie na osi 0Y
// pierwszy konstruktor klasy Point
Point() {
this(0,0p;
}
// drugi konstruktor klasy Point
Point(int newX, int newY) {

Rozdzia 2. Klasy i obiekty w Javie

43

x = newX;
y = newY;
}
//...
}

Takie zastosowanie this rzeczywicie upraszcza kod rdowy i czyni go bardziej


przejrzystym.

2.1.9. Dziedziczenie
Zanim przejdziemy dalej, naley wprowadzi pojcie dziedziczenia. Jak zwracaem
na to uwag w poprzednim rozdziale, dziedziczenie jest jedn z podstawowych cech
programowania obiektowego. Mechanizm ten umoliwia rozszerzanie moliwoci
wczeniej utworzonych klas bez koniecznoci ich ponownego tworzenia. Zasada
dziedziczenia w Javie ma za podstaw zaoenie, e wszystkie klasy dostpne w tym
jzyku bazuj w sposb poredni lub bezporedni na klasie gwnej o nazwie Object.
Wszystkie klasy pochodzce od tej oraz kadej innej s nazywane, w stosunku do tej,
po ktrej dziedzicz, podklasami. Klasa, po ktrej dziedziczy wasnoci dana klasa,
jest w stosunku do niej nazywana nadklas. Jeli nie deklarujemy w aden sposb
nadklasy, tak jak jest to pokazane w przykadowej deklaracji klasy Point, oznacza to,
e stosujemy domylne dziedziczenie po klasie Object. Formalnie deklaracja klasy
Point mogaby mie posta zaprezentowan na listingu 2.18.
Listing 2.18. Dziedziczenie po klasie gwnej
class Point extends Object {
// ...
// ciao klasy Point
// ...
}

Wytuszczony fragment listingu 2.18 deklaruje dziedziczenie po klasie Object. Jak


wczeniej pisaem, jest ono opcjonalne, to znaczy, e jeli go nie zastosujemy, Point
rwnie bdzie domylnie dziedziczy po Object.
Przedstawiony sposb jest uywany w przypadku dziedziczenia po innych klasach,
tak jak na listingu 2.19.
Listing 2.19. Praktyczne uycie dziedziczenia
class Figura extends Point {
...
}
class Wielokat extends Figura {
...
}

44

Java. Programowanie obiektowe

W przykadzie tym klasa Wielokat dziedziczy po klasie Figura, ktra z kolei dziedziczy po Point, a ta po Object. W Javie nie ma adnych ogranicze co do zagniedania
poziomw dziedziczenia. Poprawne wic bdzie dziedziczenie na stu i wicej poziomach. Jakkolwiek takie gbokie dziedziczenie jest bardzo atrakcyjne w teorii, w praktyce
wie si z niepotrzebnym obcianiem zarwno pamici, jak i procesora. To samo
zadanie zrealizowane za pomoc pytszej struktury dziedziczenia bdzie dziaao szybciej
a z trzech powodw:
t Wywoanie metod bdzie wymagao mniejszej liczby poszukiwa ich istnienia

w ramach kolejnych nadklas.

t Interpreter bdzie musia zaadowa mniej plikw z definicjami klas

(i mniej bdzie ich pniej obsugiwa).

t System operacyjny (a przez to rwnie interpreter Javy) ma wicej wolnej

pamici, a przez to pracuje szybciej.

Ponadto w przypadku apletw moemy liczy na szybsze adowanie si strony do


przegldarki, a wic bdzie to kolejna pozytywna strona.
Poza dziedziczeniem w dowolnie dugim acuchu od klasy gwnej do najniszej klasy
potomnej w niektrych jzykach programowania (na przykad C++) istnieje wielokrotne dziedziczenie jednoczenie i rwnorzdnie po kilku klasach. W Javie jest to
niemoliwe, to znaczy w definicji kadej klasy moe wystpi co najwyej jedno sowo
extends. Zamiast wielokrotnego dziedziczenia w Javie dostpny jest mechanizm interfejsw opisany w podrozdziale 2.4. Interfejsy.

2.1.10. Inicjator klasy i obiektu


Wrmy do rozwaa na temat tego, co si dzieje w pocztkach ycia obiektu. Poza
konstruktorem Java udostpnia dwa inne mechanizmy wspomagajce inicjacj i tworzenie zarwno klas, jak i obiektw. Inicjator klasy jest to blok instrukcji wykonywany
tylko raz, po zaadowaniu przez JVM pliku z klas przed pierwszym uyciem (jednak
klasa musi by uyta, eby blok ten wykona si sama deklaracja uycia bez inicjacji nie gwarantuje wykonania inicjatora klasy). Blok ten, zawarty midzy dwoma
nawiasami klamrowymi, musi by poprzedzony sowem kluczowym static (dokadne znaczenie tego modyfikatora zostanie wyjanione dalej w tym rozdziale). Poza tym
klasa moe zawiera rwnie inicjator obiektu, czyli egzemplarza klasy. Jest to te
blok instrukcji zamknity w nawiasach klamrowych, ale bez adnego kwalifikatora.
Zarwno inicjator klasy, jak i obiektu moe wystpi w kadej klasie kilkukrotnie. Jeli
jest ich wiksza ilo, zostan wykonane zgodnie z kolejnoci pojawienia si w kodzie rdowym. Poniej przedstawiony jest listing 2.20 z apletem, ktry zawiera rne
elementy inicjacyjne wraz z instrukcjami umoliwiajcymi sprawdzenie kolejnoci
ich wykonywania si (szczegy dziaania apletw zostan wprowadzone w rozdziale 3.
Aplet jako obiekt na stronie HTML). W komentarzach zaznaczono priorytet wanoci od 1 (najwaniejsze, wykonywane najpierw) do 3 (najmniej wane, wykonywane
na kocu). Elementy inicjacyjne o tym samym priorytecie wykonywane s zgodnie
z kolejnoci wystpienia. Warto zauway, e inicjator obiektu i inicjator pl obiektu
maj ten sam priorytet i wykonywane s zgodnie z kolejnoci wystpienia w klasie.

Rozdzia 2. Klasy i obiekty w Javie

45

Listing 2.20. Inicjatory klasy


import java.applet.*;
public class Applet2 extends Applet {
int i = setInt(1); // priorytet 2
static { // priorytet 1
System.err.println("class init");
}
public Applet2() { // priorytet 3
System.err.println("konstruktor");
}
{ // priorytet 2
System.err.println("instance init");
}
// dodatkowa funkcja wywietlajca
private int setInt(int i) {
System.err.println("set int: " + i);
return i;
}
int j = setInt(2); // priorytet 2
}

Zaprezentowany aplet generuje na konsol Javy w przegldarce zestaw komunikatw


pokazanych na rysunku 2.1.
Rysunek 2.1.
Wydruk generowany
przez program 2.20

class init
set int: 1
instance init
set int: 2
konstruktor

Rozszerzenie tego tematu znajduje si w paragrafie 2.1.11. Kolejno inicjacji klas.


Istnienie inicjatorw moe uproci tworzenie niektrych klas, zwaszcza tych bardziej skomplikowanych. Wyobramy sobie, e tworzymy klas z du liczb przecionych konstruktorw. W kadym z nich poza dziaaniami zwizanymi z ich charakterystyczn prac zalen od zestawu przekazanych parametrw naley wykona czynnoci
inicjujce wsplne dla wszystkich konstruktorw. Mona by to zrobi poprzez
jawne wywoanie wsplnej metody inicjujcej, jak to pokazaem na listingu 2.21.
Listing 2.21. Jawne uycie jednej metody inicjujcej
class cultiKonstruktor {
public cultiKonstruktor() { wspolnyInit(); }
public cultiKonstruktor(int i) {
wspolnyInit();
// przetwarzanie i
}
public cultiKonstruktor(String s) {

46

Java. Programowanie obiektowe


wspolnyInit();
// przetwarzanie s
}
void wspolnyInit() { /*inicjacja*/ }
}
}

Dziaanie takie jest poprawne, ale wymaga od nas pamitania o dodaniu jednego wywoania metody w kadym kolejnym konstruktorze oraz zwiksza wielko kodu wynikowego. Kady konstruktor zawiera bowiem wywoanie tej metody. Zastosowanie
inicjatora obiektu uwalnia nas od koniecznoci kadorazowego dodawania tego wywoania oraz usuwa ten fragment kodu z konstruktora. Biorc pod uwag to, e aplet
jest programem adowanym do komputera uytkownika przez internet (czasami, gdy
korzysta si z do wolnej linii telefonicznej), kade kilkadziesit czy kilkaset bajtw
moe by wane (ten sam problem dotyczy telefonw komrkowych, ktre s najczciej wyposaone w bardzo ma pami). Jeli tylko jest to moliwe, wsplny kod
inicjacyjny powinno umieszcza si w bloku inicjacyjnym. Dla klasy z listingu 2.21
rozwizanie takie miaoby posta zaprezentowan na listingu 2.22.
Listing 2.22. Kod inicjacyjny we wsplnym bloku
class MultiKonstruktor {
public MultiKonstruktor(int i) {
// przetwarzanie i
}
public MultiKonstruktor(String s) {
// przetwarzanie s
}
{ /* tu wsplna inicjacja */ }
}

Warto zauway, e zaoszczdzilimy nie tylko na dwch wywoaniach metody, ale


moglimy zrezygnowa nawet z bezparametrowego konstruktora, ktrego jedyn prac
byo uruchomienie procedury wsplnej inicjacji. Tak wic argumentem na stosowanie
takiego rozwizania jest nie tylko dbanie o uytkownikw wdzwaniajcych si do internetu, ale rwnie elegancja i prostota, ktre prawie zawsze skutkuj zmniejszeniem
liczby popenianych bdw.
Warto zwrci uwag na to, e (inaczej ni w przypadku apletw) w przypadku programw, ktre mog egzystowa samodzielnie, przed jakkolwiek inicjacj obiektu
przeprowadzana jest inicjacja statyczna, a nastpnie wykonywana jest metoda main i to
dopiero w niej moe by tworzony egzemplarz obiektu. Dzieje si tak, gdy metoda ta
jest statyczna i publiczna i moe by uyta przed stworzeniem egzemplarza obiektu
(dokadniejsze wyjanienia co do natury metod statycznych zostan zamieszczone dalej
w tym rozdziale). Maszyna wirtualna Javy jest tak skonstruowana, e wywouje t
metod jako pierwsz. W przypadku samodzielnych programw naley wic wzi
pod uwag ten aspekt i zmodyfikowa kolejno wywoywania blokw inicjacyjnych.

Rozdzia 2. Klasy i obiekty w Javie

47

2.1.11. Kolejno inicjacji klas


Powrmy do kwestii kolejnoci, w jakiej wykonuje si inicjacja klas. Zamy, e nasze
dziedziczce klasy bd skonstruowane wedug schematu pokazanego na listingu 2.23.
Listing 2.23. Bloki inicjujce w klasach dziedziczcych
class A {
A() { System.err.println("konstruktor A"); }
{ System.err.println("inicjator obiektu A"); }
static { System.err.println("inicjator klasy A"); }
}
class B extends A {
B() {System.err.println("konstruktor B"); }
{ System.err.println("inicjator obiektu B"); }
static { System.err.println("inicjator klasy B"); }
}

Pierwsze uycie pokazanej na listingu 2.23 klasy B, przy zaoeniu, e wczeniej nie
uywalimy klasy A, spowoduje wywietlenie kolejnych napisw, ktre pokazane s
na rysunku 2.2.
Rysunek 2.2.
Wydruk generowany
przez program
z listingu 2.23

inicjator klasy A
inicjator klasy B
inicjator obiektu A
konstruktor A
inicjator obiektu B
konstruktor B

Jak wic wida, najpierw w kolejnoci dziedziczenia inicjowane s klasy. Po


nich nastpuje sekwencja charakterystyczna dla inicjacji obiektw typu klasy nadrzdnej. Obiekty te nazywam egzemplarzami wirtualnymi. W praktyce JVM rezerwuje
od razu pami na cay rzeczywisty obiekt, jednak tworzenie go jest przeprowadzane
sekwencyjnie. Najpierw inicjowany jest wirtualny obiekt bazowy, pniej uzupeniane s braki przez inicjacje kolejnych klas pochodnych. Inicjacja obiektw wirtualnych, zaznaczona na rysunku 2.2 kursyw, jest blokiem nie do rozczenia. Jeli klasa
uywajca B ma blok inicjujcy klas, to zostanie on wykonany przed inicjatorem klasy A. Sytuacja nie zmieni si, jeli w pierwszej linii konstruktora klasy B dodamy jawne
wywoanie konstruktora klasy nadrzdnej (z uyciem sowa super), czyli klasy A, tak
jak pokazaem to na listingu 2.24. Odwoanie do klasy nadrzdnej dokadnie zostanie
wyjanione w paragrafie 2.1.14. Odwoanie do klas nadrzdnych.
Listing 2.24. Rozszerzenie inicjacji klas z listingu 2.23
class B extends A {
B() {
super();
System.err.println("konstruktor B");
}
{ System.err.println("inicjator obiektu B"); }
static { System.err.println("inicjator klasy B"); }
}

48

Java. Programowanie obiektowe

Zgodnie z tym, co wczeniej napisaem, konstruktor klasy nadrzdnej wywoywany


jest domylnie jako pierwsze dziaanie konstruktora danej klasy.
Z sekwencyjnym tworzeniem i inicjacj obiektw dziedziczcych zwizany jest pewien wany problem. Poka go na przykadzie klasy nadrzdnej o postaci zaprezentowanej na listingu 2.25.
Listing 2.25. Klasa, po ktrej trudno dziedziczy
public class A {
private Object o;
public A(Object o) {
this.o = o;
}
}

Klasa taka nie umoliwia utworzenia dziedziczenia w postaci zaprezentowanej na listingu 2.26.
Listing 2.26. Bdne dziedziczenie po klasie z listingu 2.25
public class B extends A {
Object oo = new Object();
public B() {
super(oo); // bd
}
}

W takim przypadku konstruktor klasy nadrzdnej, reprezentowany przez lini super(oo),


jest wywoywany, zanim utworzony zostanie egzemplarz oo klasy Object. Przed konstruktorem klasy nadrzdnej nie moe bowiem by wykonywana adna inna akcja poza ewentualnym wywoaniem innego konstruktora przecionego, ktry wywoa konstruktor super. Podobnie niepoprawna bdzie te konstrukcja pokazana na listingu 2.27.
Listing 2.27. Bdne dziedziczenie po klasie z listingu 2.25
public class B extends A {
public B() {
super(this); // bd
}
}

Bd wynika z tego, e egzemplarz obiektu tej klasy, reprezentowany przez this, bdzie
znany dopiero po jego utworzeniu, a wic najwczeniej po zakoczeniu pracy konstruktora klasy nadrzdnej.
Mimo takiego podejcia, to znaczy kolejnego tworzenia egzemplarzy obiektw klas
dziedziczcych, metody tych klas s formalnie dostpne w obiektach nawet przed ich
utworzeniem. Moe to spowodowa powstanie bdnego, przynajmniej w naszym
pojciu, dziaania niektrych konstruktorw. Na listingu 2.28 zaprezentowane zostay
dwie klasy A i B. W klasach tych metoda doSth zostaa zadeklarowana i wykorzystana niepoprawnie.

Rozdzia 2. Klasy i obiekty w Javie

49

Listing 2.28. Bdne deklaracje metody w klasach dziedziczcych


class A {
A() {
doSth();
}
void doSth() {
System.err.println("A.doSth");
}
}
class B extends A {
B(){
super();
doSth();
}
void doSth() {
System.err.println("B.doSth");
}
}

Jeli zadeklarujemy uycie klasy B i utworzenie z niej obiektu


B b = new B();

otrzymamy niespodziewany dla wikszoci osb wynik (wydruk na konsoli Javy):


B.doSth
B.doSth

Zaobserwowany efekt dziaania jest jednak poprawny. Jest on skutkiem dziaania polimorfizmu. W zaprezentowanym przykadzie konstruktor w klasie A wywouje metod
doSth tworzonego obiektu (czyli klasy B). Tak wic to metod tej klasy wywoa konstruktor klasy A, mimo i twrca mia zapewne co innego na myli. Aby wywoanie
doSth zawsze dotyczyo wasnej klasy, metoda ta musi by prywatna (modyfikator
private). Warto na to zwrci uwag, gdy moe to by przyczyn wielu podobnych
nieporozumie. Inicjacja klasy:
B b = new B(3);

ktrej definicja pokazana jest na listingu 2.29, moe przynie nieoczekiwany efekt.
Listing 2.29. Uycie metod w konstruktorze
public class A {
public A() {
System.out.println("wewntrz konstruktora A");
doSth();
}
public void doSth() {
System.out.println("nic nie robi");
}
}
public class B extends A {
private int p1;
public B(int p) {

50

Java. Programowanie obiektowe


p1 = p;
System.out.println("wewntrz konstruktora B");

}
public void doSth() {
System.out.println("p1=" + p1);
// obliczenia z uyciem p1
}

Pozornie nieoczekiwany wynik dziaania klasy z listingu 2.29 zaprezentowaem na


rysunku 2.3.
Rysunek 2.3.
Wydruk generowany
przez program 2.29

wewntrz konstruktora A
p1=0
wewntrz konstruktora B

Czyli tak jak napisaem wczeniej, przed uruchomieniem konstruktora klasy B (czyli
przed powstaniem egzemplarza tej klasy) system potrafi ju uy jego metody doSth.
Oczywicie skoro dzieje si to przed uruchomieniem konstruktora B, prywatne pole p1
nie jest jeszcze zainicjowane, wic jest rwne zero. Wicej na temat polimorfizmu
znajdziesz w paragrafie 2.2.6. Efekty polimorfizmu.

2.1.12. Destruktor
Podchodzc formalnie do specyfikacji JVM, mona powiedzie, e klasy Javy nie
wymagaj stosowania specjalizowanych metod zwalniajcych zajt przez siebie pami. Wynika to z zaoenia przyjtego w czasie tworzenia tego systemu, a mianowicie braku jawnego zwalniania pamici zajmowanej przez obiekty. Podejcie klasyczne
stosowane w C++ i Object Pascalu zakada, e to programista, w chwili kiedy uznaje
to za stosowne lub gdy wymusza to struktura programu, zwalnia pami, korzystajc
z jawnych funkcji systemowych bd specjalizowanych metod wbudowanych w obiekty
(destruktory). Podejcie takie ma t zalet, e umoliwia zwalnianie pamici natychmiast, kiedy jest to moliwe. Ma jednak t wad, e moe powodowa prby
odwoania si do obiektu omykowo i przedwczenie zwolnionego. W Javie zrezygnowano wic z tego mechanizmu. Nie oznacza to jednak braku metody, ktra byaby
namiastk destruktora. Jest ni metoda finalize wywoywana w trakcie czyszczenia
pamici. Ma ona za zadanie wykona wszystkie konieczne dziaania przed cakowitym
zastopowaniem oraz zwolnieniem pamici przez obiekt, do ktrego naley (jednak
zwalnianie pamici nie naley ju do obowizkw tej metody). Typowa deklaracja
funkcji koczcej dziaanie obiektu powinna mie posta pokazan na listingu 2.30.
Listing 2.30. Przykadowa deklaracja destruktora
public void finalize() {
zatrzymajWatki();
usunPowiazania();
}

Rozdzia 2. Klasy i obiekty w Javie

51

W ramach dziaania tej metody poza zatrzymaniem wtkw przynalenych do tego


obiektu (o wtkach napisz szerzej w rozdziale 6. Programowanie wielowtkowe)
powinno si dokona wszelkiego sprztania po dziaajcym obiekcie. Jeli obiekt sam
siebie wywietla na ekranie, naley ten obraz usun (w przeciwnym razie moe pozosta tam na zawsze). Jeli obiekt by wykorzystywany jako nasuchujcy w procesie
zarzdzania zdarzeniami, naley go usun z kolejki obsugi zdarze obiektu, ktry
by przez niego obsugiwany. Jeli z dziaaniem obiektu zwizana bya obsuga plikw bd dostp do baz danych, naley zakoczy t obsug, aby pliki nie byy blokowane przez nieistniejcy ju obiekt. Po zakoczeniu tej metody sterowanie oddawane jest do wirtualnej maszyny Javy, ktra wykonuje fizyczne zwalnianie pamici
(garbage collection). Nie wszystkie maszyny dokonuj tego natychmiast po zakoczeniu pracy destruktora, ale nie wpywa to na sposb dziaania programu.

2.1.13. Przykrywanie metod


W miar jak tworzymy kolejne klasy pochodne od innych, pojawia si czsto sytuacja, e musimy zastpi dziaanie pewnej metody inn, o takiej samej nazwie i tym
samym zestawie parametrw. Dziaanie takie nazywa si przykrywaniem, pokrywaniem bd nadpisywaniem metod. Na listingu 2.31 przedstawiam 3 kolejne klasy w acuchu dziedziczenia, ktre przykrywaj po kolei swoj metod info.
Listing 2.31. Trzy klasy pokrywajce jedn metod
class A {
public void info() {
System.err.println("Jestem w klasie A");
}
}
class B extends A {
public void info() {
System.err.println("Jestem w klasie B");
}
}
class C extends B {
public void info() {
System.err.println("Jestem w klasie C");
}
}

Odwoanie do metody info obiektu klasy C powoduje wywietlenie na konsoli Javy


w przegldarce napisu:
Jestem w klasie C

Nie jest to nic dziwnego, bo w klasie C metoda info przykrya swoj odpowiedniczk
z klasy B, ktra z kolei przykrya swoj odpowiedniczk z klasy A. Naley jednak pamita, e domylnie wszystkie metody w Javie s wirtualne. Zwizana jest z tym
kwestia polimorfizmu, to znaczy wywoanie metody ustalane jest na podstawie rzeczywicie uywanego obiektu, a nie jego deklaracji typu (chyba e s to metody statyczne). Wicej na ten temat znajdziesz w paragrafie 2.2.6. Efekty polimorfizmu.

52

Java. Programowanie obiektowe

2.1.14. Odwoanie do klas nadrzdnych


Nie zawsze jednak przykrywanie metod jest podanym efektem. Mog zaj sytuacje, w ktrych mimo tego e mamy przykryte pewne metody, chcielibymy odwoa
si do nich, gdy wiemy, e wykonuj przydatne dla nas dziaanie. Dokonuje si tego
poprzez referencj super (jest to to samo sowo kluczowe, ktrego uywa si do wywoania konstruktora klasy nadrzdnej). Na listingu 2.32 przedstawiona jest zmodyfikowana klasa C, ktra pokae, jak odwoa si do metody swojej klasy nadrzdnej,
mimo e metoda ta jest przykryta.
Listing 2.32. Sposb odwoania do metody klasy nadrzdnej
class C extends B {
public void show() {
info();
super.info(p;
// super.super.info(); <- bd kompilacji
}
public void info() {
System.err.println("Jestem w klasie C");
}
}

Efekt uycia w aplecie klasy C i jej metody show przedstawiony jest na rysunku 2.4.
Rysunek 2.4.
Wydruk generowany
przez program 2.32

Jestem w klasie C
Jestem w klasie B

Do poprawnej pracy trzeba byo zastosowa sowo kluczowe super, ktre umoliwia
cofnicie si wstecz acucha dziedziczenia, niestety tylko o jeden poziom (zaznaczyem
to listingu 2.32 wytuszczonym komentarzem w kodzie). Jedyn moliwo cofnicia
si wstecz dalej ni poza najblisz klas jest stosowanie metod bd klas statycznych.
Moliwo taka nie wynika wtedy jednak z efektu cofania si w acuchu dziedziczenia,
a z oglnych cech modyfikatora static. Dalsze cofanie jest rwnie moliwe w przypadku potraktowania obiektw jako refleksyjnych. Naley jednak zaznaczy, e prba
dalekiego i gbokiego cofania si wiadczy o nie najlepszym projekcie, ktry posuy
do stworzenia naszej klasy. Jeli wic czujemy potrzeb takiego gbokiego cofania si,
powinnimy, zamiast prbowa j zrealizowa, ponownie przemyle projekt klasy.
Sowo super moe by rwnie wykorzystane w konstruktorze, bardzo podobnie jak
this. Jednak w przypadku this chodzio o odwoanie do innego konstruktora w tej
samej klasie, na tym samym poziomie dziedziczenia, ale z inn liczba parametrw
(czyli do jednego z przecionych konstruktorw). W przypadku sowa super odwoujemy si do konstruktora klasy nadrzdnej. Sposb uycia pokazany jest we fragmencie konstruktora klasy Test:
public Test(int a, string b) {
super(a, b);
System.err.println(b);
}

Rozdzia 2. Klasy i obiekty w Javie

53

W tym przykadzie konstruktor klasy Test wykonuje dokadnie to samo, co konstruktor


jego klasy nadrzdnej, oraz dodatkowo wywietla cig tekstowy przekazywany w parametrze b. Naley pamita, e odwoanie do konstruktora klasy nadrzdnej, jeli
wystpuje, musi by pierwsz instrukcj w konstruktorze. Jedynym wyjtkiem jest odwoanie do innego konstruktora w tej samej klasie z uyciem sowa this. Jeli chcemy
jawnie wywoa konstruktor nadklasy, wtedy ten drugi konstruktor, do ktrego odnosimy si przez this, musi ju uy odwoania super w pierwszym wierszu metody.

2.1.15. Odwoanie do pl klas nadrzdnych


Pewn namiastk odwoania do klas nadrzdnych na dowoln gboko acucha dziedziczenia jest odwoanie do pl pokrywanych w kolejnych podklasach, co postaram
si pokaza na listingu 2.33.
Listing 2.33. Klasa dziedziczca cechy bez modyfikacji
class A {
String info = "klasa A";
}
class B extends A { }

Formalnie, jeli pole nie jest prywatne, konstrukcja zaprezentowana na listingu 2.33
oznacza, e klasa B posiada pole o nazwie info typu String zawierajce tekst "klasa A".
Nie stosuje si wic ponownego definiowania tego pola, nawet jeli chcemy je wykorzysta w inny sposb, ni pierwotnie zakadalimy w klasie A. Moemy jednak zastosowa pokrycie pl w klasie, tak jak pokazano to na listingu 2.34.
Listing 2.34. Pokrywanie pl w klasie dziedziczcej
class A {
String info = "klasa A";
}
class B extends A {
String info = "klasa B";
}
class C extends B {
String info = "klasa C";
public void show() {
System.err.println(((A)this).info);
}
}

Jeli wywoamy metod show obiektu klasy C na konsoli Javy, zobaczymy napis:
klasa A

Takie zachowanie, rnice si od zachowania metod, wynika z faktu, e odwoywanie


si do metod zaley od faktycznego typu obiektu, ktrego w danym momencie uywamy. Natomiast w stosunku do pl uywany jest zadeklarowany typ obiektu. Jest to

54

Java. Programowanie obiektowe

wynik dobrze przemylanej metodologii realizacji idei obiektowej i nazywa si przesanianiem pl. Mechanizm ten pojawi si jako rozszerzenie moliwoci dziedziczenia. Tworzc now klas, jej autor moe stworzy nowe pole o nazwie wykorzystywanej ju w klasie nadrzdnej (specjalnie bd przez pomyk). Gdyby tak utworzone
pole uniemoliwiao dostp do pola klas nadrzdnych (tak jak to si dzieje w przypadku metod), wewntrzne odwoania do pl klasy nadrzdnej zaczyby si teraz
odnosi do pl nowej klasy, by moe nieznanej nawet autorowi klasy nadrzdnej.
Mogoby to skutecznie zakci dziaanie nadklasy, a co za tym idzie i podklasy, w ktrej
zadeklarowano pole o uywanej ju nazwie. Biorc pod uwag fakt, e Java nie ogranicza w aden sposb gbokoci dziedziczenia, mogoby si okaza, e w pewnym
momencie zabraknie nam logicznych nazw do okrelenia kolejnych pl.
Problem ten jest kolejnym argumentem przemawiajcym za stosowaniem ortodoksyjnie pojtej hermetyzacji klas, to znaczy maksymalnie du liczb pl powinno deklarowa si jako prywatne. Problem taki nie miaby wtedy prawa si pojawi.
Naley rwnie pamita, e mimo stosowania referencji do pl zgodnych z deklarowanym typem, problem nie pojawi si w przypadku stosowania podrcznikowej konstrukcji klas B i C pokazanej na listingu 2.35.
Listing 2.35. Inicjacja pl w klasach dziedziczcych w inicjatorze
class B extends A {
{ info = "klasa B"; }
}
class C extends B {
{ info = "klasa C"; }
public void show() {
System.err.println(((A)this).info);
}
}

Stosujc wycznie inicjacj pola info waciw wartoci, bez deklarowania tego
pola na nowo, po uyciu obiektu klasy C na konsoli zobaczymy napis:
klasa C

Wynik bdzie wic zgodny z oczekiwaniami.

2.1.16. Klasy abstrakcyjne


Klasy abstrakcyjne to szczeglny rodzaj klas, ktry przenosi obowizek implementacji
niektrych bd wszystkich metod do swoich podklas. Mechanizm ten jest przydatny
w przypadku, gdy cz zachowania jest wsplna dla wszystkich klas pochodnych,
a cz jest charakterystyczna tylko dla klas pochodnych, natomiast dla wsplnej nadklasy nie miaaby adnego sensu. W takim przypadku czci tej nie implementuje si
w klasie nadrzdnej z zaoeniem, e zostanie to zaimplementowane w podrzdnej.
Wyrnikiem tego, e klasa jest abstrakcyjna, jest sowo kluczowe abstract okrelajce

Rozdzia 2. Klasy i obiekty w Javie

55

klas zawierajc przynajmniej jedn pust deklaracj oraz wszystkie metody, ktre
s wycznie deklarowane. Przykad klasy abstrakcyjnej pokazany jest na listingu
2.36. Fakt, e klasa jest abstrakcyjna,, wynika z braku implementacji metody getInfo.
Listing 2.36. Przykadowa klasa abstrakcyjna
abstract class Obliczenia {
abstract public String getInfo();
public void doMath() {
// ciao metody
}
}

W przypadku prby dziedziczenia po takiej abstrakcyjnej klasie wszystkie metody


abstrakcyjne musz zosta pokryte. W przeciwnym wypadku klasa dziedziczca rwnie
bdzie abstrakcyjna. Klasa abstrakcyjna nie moe posuy jako wzorzec do utworzenia egzemplarza klasy. Tak wic zastosowanie klasy abstrakcyjnej to sposb na
wymuszenie implementacji pewnych metod w programie uywajcym naszych klas.
Poza klasami abstrakcyjnymi podobnym mechanizmem s interfejsy, ktre zostan
opisane dalej w tym rozdziale. Przeprowadz tam krtkie porwnanie klas abstrakcyjnych i interfejsw oraz przypadkw wskazanych do ich zastosowania. Jedyn z zalet niedostpnych w interfejsach, ktr ma mechanizm klas abstrakcyjnych, jest moliwo
uczynienia abstrakcyjnymi niektrych klas majcych wczeniej penoprawn funkcjonalno. Mona tego dokona, pokrywajc w klasie pochodnej jedn lub wicej
metod metodami abstrakcyjnymi, czyli bez implementacji. Dziki temu moemy
usun standardow implementacj metod, wymuszajc ich przysz, waciwsz
dla danej klasy implementacj.

2.2. Obiekty
Jak kilkukrotnie zwracaem ju uwag, klasy s tylko definicj i okreleniem sposobu
dziaania bd przechowywania informacji. Aby klasa moga by uyta, musimy
utworzy jej egzemplarz, ktrym jest obiekt. Istniej dwa podstawowe sposoby tworzenia obiektw zdefiniowanych typw tak aby byy jawnie dostpne oraz w sposb
niejawny. Poniej przedstawi rnice midzy nimi. Ponadto sprbuj zwrci uwag na
wszystkie wane zagadnienia zwizane z tworzeniem i egzystowaniem obiektw w Javie.
W dalszej czci tego rozdziau poka rwnie sposb tworzenia obiektw z uyciem
refleksji (typy tych obiektw nie musz by znane w czasie tworzenia programu).

2.2.1. Rozwaania o adresie


Przed przystpieniem do praktycznych przykadw tworzenia obiektw powiniene,
zwaszcza jeli znasz inne jzyki programowania, dowiedzie si, co wie si z powstaniem pojedynczego egzemplarza klasy. W C++ czy Object Pascalu utworzenie
egzemplarza zmiennej typu obiektowego wizao si z przydzieleniem jej pewnego

56

Java. Programowanie obiektowe

obszaru pamici (jawnie bd nie, rcznie bd automatycznie). Zmienna typu obiektowego przechowywaa wycznie wskazanie na obszar, w ktrym znajdowa si obiekt,
bd na miejsce, gdzie znajdowa si opis obiektu i dalsze adresy pl oraz metod.
W Javie, wbrew obiegowym opiniom, jest dokadnie tak samo. Zmienna reprezentujca obiekt to rzeczywicie wskazanie (albo wedug innego nazewnictwa adres) na
blok rozpoznawany przez maszyn wirtualn Javy jako zbir wszystkich potrzebnych
informacji do jednoznacznego zidentyfikowania obiektu i poprawnego uywania go.
Na tym jednak koczy si podobiestwo midzy wskazaniem na obiekt w Javie a w innych jzykach. W Javie nie da si wykona kilku podstawowych operacji dostpnych w C++ czy Object Pascalu. Nie da si utworzy samoistnego obszaru pamici
i wymusi potraktowanie go przez kompilator bd interpreter jako obiekt. Nie da si
doda do wskanika liczby bdcej wielokrotnoci dugoci sowa maszynowego,
aby odwoa si bezporednio do pola, metody bd nastpnego obiektu w pamici.
Najwicej trudnoci sprawia natomiast przyzwyczajenie si do tego, e obiekt, ktry
nie jest ju przez nas uywany, nie moe by zwolniony na nasze danie, tylko musimy zda si przy tym na ask JVM. Jednak te trzy ograniczenia sprawiaj, e Java
jest jzykiem, ktry wynosi bezpieczestwo kilka krokw naprzd, przed inne jzyki.
Dostajemy zalety pracy na wskanikach i pozbawieni jestemy moliwoci wiadomego (bd nie) zniszczenia sobie dziaajcego programu. W dalszej czci ksiki
bd uywa zamiennie nazwy obiekt, egzemplarz, adres bd wskazanie. Nie powinno
Ci to jednak zwie. Bd cay czas mwi o tym samym o symbolicznej reprezentacji pojedynczego egzemplarza klasy.
Zanim przejdziemy do praktycznego stosowania obiektw, chciabym przypomnie,
e w Javie udostpniony jest mechanizm kompatybilnoci typw obiektowych wynikajcych z dziedziczenia klas. To znaczy moemy zadeklarowa obiekt jako egzemplarz klasy dokadnie tego samego typu, jaki tworzymy, albo jako egzemplarz dowolnej klasy nadrzdnej tego obiektu, czyli takiej, ktra znajdowaa si w acuchu jego
dziedziczenia. W skrajnym przypadku moemy wic deklarowa w Javie wszystkie
obiekty jako egzemplarze klasy Object, po ktrej dziedzicz wszystkie klasy w Javie.
Takie podejcie, jakkolwiek formalnie suszne i niezmniejszajce (dziki mechanizmowi
polimorfizmu) funkcjonalnoci programu, w praktyce jest bardzo uciliwe. Wymaga
bowiem od programisty cigego umieszczania referencji typu obiektu w momencie
odwoywania si do pl czy metod istniejcych wycznie w klasach pochodnych.
Interpreter zna cile typ obiektu w czasie uruchomienia programu, ale kompilator
w czasie kompilacji nie jest tego w stanie stwierdzi. Tak wic prociej jest uywa
zmiennych waciwego typu. Moliwo stosowania typu nadrzdnego powinno pozostawi si wycznie do sytuacji wyjtkowych, kiedy jest to wytumaczone potrzeb
uproszczenia bd zwikszenia funkcjonalnoci projektu.

2.2.2. Jawne uycie obiektw


Rozpoczcie tworzenia obiektu naley zacz od deklaracji uycia egzemplarza konkretnego typu. Poza typem i modyfikatorem musi ona zawiera unikaln nazw, ktra
umoliwi przysz identyfikacj obiektu. Przykad takiej deklaracji podany jest poniej:
Button b;

Rozdzia 2. Klasy i obiekty w Javie

57

W przykadzie tym pod nazw b bdzie si w przyszoci ukrywa obiekt klasy Button
(nalecy do standardowej biblioteki AWT). Bdzie, poniewa bezporednio po deklaracji zmienna b nie reprezentuje jeszcze adnego konkretnego wskazania. Sama
deklaracja powoduje przypisanie zmiennej wartoci null. To znaczy kompilator wie
ju, e zmienna b jest odpowiedniego typu i moemy z jej pomoc odwoa si do pl
i metod klasy Button, jednak brak nam jeszcze samego obiektu. Dopiero konstrukcja:
b = new Button();

fizycznie tworzy jej pojedynczy egzemplarz. W praktyce operator new rezerwuje pami potrzebn dla danego obiektu, inicjuje waciwe pola w tym egzemplarzu oraz
zwraca do zmiennej b adres zarezerwowanego bloku pamici. Warto wiedzie, e wielko i sposb rezerwacji pamici nie zaley od typu zmiennej zadeklarowanej wczeniej, lecz od konstruktora. To on, a nie deklaracja zmiennej, determinuje wynik tworzenia egzemplarza. Ponadto powinno si te pamita o tym, e wywoanie new
skojarzone jest rwnie ze sprawdzeniem, czy wskazana klasa bya wczeniej uywana
i czy jest zaadowana do pamici. Jeli nie, jest ona znajdowana na dysku bd w sieci
i adowana do pamici. Po zaadowaniu, jeli w klasie wystpuje jej inicjator, uruchamiany jest jego kod. Dopiero po tym procesie nastpuje przejcie do faktycznej
realizacji zada skojarzonych z operatorem new.
Poza konstrukcj pokazan powyej, czyli osobno deklarujemy zmienn typu obiektowego i osobno tworzymy egzemplarz klasy, moemy te operacje wykona w sposb
spjny, umieszczajc je w jednym wierszu programu:
Button b = new Button();

Z konwencji takiej korzysta si najczciej wtedy, gdy zmienna obiektowa uywana


jest wycznie w obrbie jednej metody bd obiekt moe by utworzony globalnie
i deklaracja zmiennej znajduje si poza ciaem jakiejkolwiek metody. Jeli jednak
obiekt ma by dostpny w caej klasie, lecz jego inicjacja uzaleniona jest od innych dodatkowych czynnikw bd czynnoci, naley zastosowa rozczn deklaracj i tworzenie
obiektu. Najczciej obiekt tworzy si wtedy w konstruktorze, tak jak na listingu 2.37.
Listing 2.37. Rozczne deklarowanie i tworzenie obiektu
class DemoPanel extends Panel {
Button b;
public DemoPanel() {
b = new Button();
b.setLabel("przycisk");
}
}

Moment tworzenia obiektw jest dobry, aby przypomnie o kwestii przecienia konstruktorw. Stosowany w tym paragrafie ju trzy razy przykad bazowa na wykorzystaniu bezparametrowego konstruktora, ktry tworzy przycisk ekranowy bez adnego
napisu. Dodanie napisu na tym przycisku wymaga uycia metody setLabel, co pokazano na ostatnim przykadzie. Obie operacje mona poczy, korzystajc z innego
konstruktora, ktry tworzy od razu przycisk z opisem:
b = new Button("przycisk");

Jak wida, jest to prostsze rozwizanie, co wcale nie oznacza, e trzeba je zawsze stosowa.

58

Java. Programowanie obiektowe

2.2.3. Kopiowanie obiektw


Egzemplarz obiektu identyfikowany przez nazw symboliczn w wielu przypadkach
moe by traktowany dokadnie tak samo jak egzemplarz zmiennej prostej. Istniej
jednak wyjtki od tej reguy. Konstrukcja poprawna dla typw prostych:
int i, j;
i = 1;
j = i;

nie jest dla obiektw merytorycznie suszna, chocia pod wzgldem formalnym jest
jak najbardziej poprawna. Przypisanie jednej zmiennej prostej do innej skutkowao
wycznie przypisaniem wartoci jednej zmiennej do drugiej. Konstrukcja:
Button b = new Button();
Button c;
c = b;

powoduje wycznie przepisanie adresw, a wic zmienne b i c wskazuj na jeden, ten


sam obiekt. Nie mamy wic dwch obiektw, jak to si pozornie wydaje, a tylko jeden,
do ktrego mamy dwie referencje. Wykonujc operacj zmiany napisu na przycisku:
c.setLabel("przycisk 2");

tak naprawd zmieniamy tekst w obu referencjach. Istnienie dwch referencji do jednego obiektu moemy zredukowa do jednej bez zmiany drugiej, przypisujc do jednej z nich warto pust null:
b = null;

Po tej akcji zmienna b nie wskazuje ju na aden obiekt. Natomiast c wskazuje na


przycisk ekranowy, ktry by wczeniej utworzony na potrzeby zmiennej b, czyli c
nie utracio referencji. Co wicej, obiekt wskazywany przez c nie zostanie zwolniony
przez system zwalniania wolnej pamici Javy. JVM zwalnia bowiem pami po zajmowanych obiektach, ale pod warunkiem e nie s one ju uywane, to znaczy adna
nazwa symboliczna znajdujca si w aktualnej przestrzeni nazw na nie nie wskazuje.
W dziaaniu takim uwidacznia si bezpieczestwo Javy, ktra nie umoliwia rcznego
zwolnienia pamici. Gdyby bowiem po powieleniu adresu obiektu na jednej z kopii
dao si wykona dziaania destruktora, zniszczyby on rwnie drug. Uytkownik,
nie majc wiadomoci tego faktu, poprzez uycie zwolnionego obiektu mgby spowodowa bdy w dziaaniu.
Jednak poprawne kopiowanie obiektw, to znaczy tworzenie ich kopii bez wywoywania konstruktora klasy, jest moliwe. Do tego celu stworzona zostaa metoda clone.
Tworzy ona nowy egzemplarz obiektu, podobnie jak operator new, i wypenia wszystkie jego pola wartociami ustawionymi w tym obiekcie, ktrego kopi tworzymy.
Jednak metoda clone nie jest dostpna w prosty sposb z dowolnego obiektu. Aby
mona byo jej uy, obiekt, ktry zamierzamy powiela, musi spenia dwa warunki
pokrywa oryginaln metod clone z uwzgldnieniem moliwoci powstania wyjtkw oraz implementowa interfejs Cloneable (o interfejsach i implementacji przeczytasz dalej w tym rozdziale). Przykadowa klasa ze szcztkow obsug bdw,
ktra moe by powielana za pomoc swojej metody clone, przedstawiona jest na listingu 2.38.

Rozdzia 2. Klasy i obiekty w Javie

59

Listing 2.38. Definicja klasy, ktrej obiekty mog by powielane


class A implements Cloneable {
int i1, i2;
public Object clone() {
try { return super.clone(); }
catch(Exception e)
{ return null; }
}
}

Jej uycie przedstawione jest na listingu 2.39.


Listing 2.39. Powielanie obiektw z listingu 2.38
public class Applet2 extends Applet {
A a1 = new A();
A a2;
public void init() {
a1.i1 = 1;
a1.i2 = 2;
a2 = (A)a1.clone();
a2.i1 = 3;
a2.i2 = 4;
System.err.println(a1.i1);
System.err.println(a1.i2);
}
}

Dla upewnienia si, e powstay dwa rne obiekty, zastosowaem tu zmian wartoci
pl jednego z nich i sprawdzenie, czy pola drugiego nie zmieniy si. W wyniku
dziaania tego programu na konsoli przegldarki zobaczymy liczby 1 i 2. Oznacza to,
e rzeczywicie mamy do czynienia z dwoma rnymi egzemplarzami. Gdyby zamiast uycia metody klonujcej zastosowa proste podstawienie obiektw, o ktrym
ju wczeniej pisaem, e jest niepoprawne:
a2 = a1;

na konsoli zobaczylibymy liczby 3 i 4. Oznaczaoby to, e mamy co prawda dwie referencje do obiektw, ale obie do jednego egzemplarza. To znaczy nie mamy dwch
kopii obiektu, ale dwa wskazania na jeden obiekt.

2.2.4. Niejawne uywanie obiektw


Rezerwowanie dla obiektu nazwy symbolicznej ma sens jedynie wtedy, gdy w dalszej
czci programu zamierzamy go wykorzystywa. S jednak sytuacje, kiedy obiekt
tworzony jest doranie wycznie na potrzeby jednorazowej akcji i nie zamierzamy
si ju do niego nigdy odwoywa. Tak na przykad moe by w przypadku etykiet
umieszczanych w programie w celach informacyjnych. Raz umieszczon etykiet
zamierzamy pozostawi w tym miejscu, gdzie j umiecilimy, bez adnych zmian.

60

Java. Programowanie obiektowe

Nie interesuje nas odwoanie do niej (chocia w praktyce wyglda to tak, e system
bdzie to robi za nas w sposb niejawny). W takim przypadku moemy skorzysta
z niejawnej metody tworzenia obiektw pokazanej na listingu 2.40.
Listing 2.40. Inicjacja etykiety bez nadania nazwy jej zmiennej
class DemoPanel extends Panel {
public DemoPanel() {
this.add(new Label("napis informacyjny"p, nullp;
}
}

W pokazanym przykadzie obiekt tworzony jest wycznie po to, aby mona go byo
uy w metodzie add, ktra dodaje napis informacyjny do naszego panelu. Korzystamy
tu z wiedzy o sposobie wywoywania metod w Javie. Ot parametry przekazywane
do tych metod s wyliczane przed ich wywoaniem. W zwizku z tym przedstawiona
konstrukcja powoduje, e przed przekazaniem w postaci parametru uruchamiany jest
konstruktor nowego obiektu klasy Label, ktrego adres przekazywany jest jako parametr. Oczywicie niejawne uycie nie oznacza wcale, e obiekt istnieje tylko przez
czas wykonywania metody add. Wewntrz tej metody obiekt przypisywany jest do
pojedynczego elementu nowej zmiennej tablicowej typu umoliwiajcego przechowywanie takich obiektw. W zwizku z tym, korzystajc ze spostrzeenia poczynionego wczeniej, wytuszczona linia mogaby by rozwinita bez zmiany funkcjonalnoci do postaci:
Label l = new Label("napis informacyjny");
this.add(l, null);
l = null;

W zwizku z niepotrzebn rozwlekoci kodu i niecelowym zablokowaniem nazwy


zmiennej na potrzeby jednorazowej akcji naturalne jest uycie niejawnej formy utworzenia obiektu, ktra nie wymaga rezerwacji nazwy zmiennej.

2.2.5. Typ zmiennej i obiektu. Operator instanceof


W dotychczasowych przykadach uywania obiektw typ zmiennej, ktry suy do
ich przechowywania, by dokadnie taki, jak ich typ. Takie rozwizanie jest jak najbardziej suszne i najczciej uywane. Nie oznacza to jednak, e jest to jedyny sposb na deklarowanie zmiennych obiektowych. Czsto zdarza si, e w celu zwikszenia
funkcjonalnoci programu deklarujemy zmienn innego typu, ni w efekcie bdziemy
wykorzystywa. W bezpieczny sposb moemy deklarowa typ zmiennej jako typ
nadklasy klasy, ktrej bdziemy uywali. Moemy wic zadeklarowa, a nastpnie utworzy zmienn z uyciem konstrukcji:
Object b;
b = new Button("przycisk");

Taka konstrukcja nazywa si bezpieczn konwersj typu, konwersj w gr lub rozszerzaniem zakresu zmiennej. Dalsze uycie zmiennej b moe okaza si utrudnione, gdy

Rozdzia 2. Klasy i obiekty w Javie

61

bdziemy chcieli wykorzysta cechy obiektu charakterystyczne nie dla typu zmiennej,
a dla rzeczywistego typu obiektu. Bez problemw moglibymy uy dla tej zmiennej
metody toString zadeklarowanej w klasie Object, ktra zwraca tekstow reprezentacj tego obiektu. Jednak wstawienie obiektu typu przycisk ekranowy (Button) do graficznego obrazu programu wymaga uycia funkcji add, ktra oczekuje, e parametr jej
wywoania bdzie obiektem typu Component lub obiektem typu pochodnym. W zwizku
z tym, e Object jest klas nadrzdn dla Component, uycie zmiennej typu Object nie
zostanie zaakceptowane:
add(b, null);

// jeli b typu Object, to bd

Jeli mamy pewno, e b jest typu Button (lub Component, po ktrym dziedziczy Button),
wtedy moemy uy jawnej konwersji typu Object na typ akceptowany przez metod add:
add((Component)b, null);

Takie wywoanie zostanie zaakceptowane przez kompilator. W wywoaniu tym zastosowalimy niebezpieczn konwersj typu, konwersj w d bd zwenie typu zmiennej.
Jeli konwersja jest poprawna, to znaczy zmienna b reprezentuje obiekt typu Component
lub pochodny od niego, wtedy wszystko zadziaa dobrze. Gdyby jednak okazao si,
e b nie przechowuje obiektu typu Component ani adnego innego od niego pochodzcego, wtedy wystpi bd (konkretnie bdzie to wyjtek ClassCastException), ktry
wstrzyma wykonanie programu wykonanie. Gdyby konwersja bya niepoprawna ju
na etapie kompilacji, to znaczy prbowalibymy konwertowa typ obiektw midzy
dwoma gaziami dziedziczenia, wtedy bd wystpiby ju na etapie kompilacji.
Zdarza si, e aby podnie uniwersalno niektrych fragmentw programu, z zaoenia stosuje si klas nadrzdn jako typ zmiennej. Czsto, niemal nagminnie, stosuje si takie rozwizanie w przypadku przekazywania obiektw poprzez parametry
do wntrza metod. Nie mamy wtedy adnej pewnoci, jakiego typu obiekt odbieramy.
Do obsugi takich sytuacji Java posiada operator instanceof, ktry umoliwia zbadanie typu egzemplarza klasy. W praktyce dokonuje on porwnania typu egzemplarza
klasy z typem klasy. Przykad jego uycia pokazany jest na listingu 2.41.
Listing 2.41. Przykadowe badanie typu obiektu
public void UseObject(Object comp) {
if (comp instanceof Button) {
// obsuga obiektu typu Button
} else if (comp instanceof Label) {
// obsuga obiektu typu Label
} else {
// obsuga innych obiektw
}
}

Takie podejcie zapewnia zabezpieczenie programu przed nieoczekiwanymi przerwami w pracy oraz umoliwia wprowadzenie do niego wikszej funkcjonalnoci.

62

Java. Programowanie obiektowe

2.2.6. Efekty polimorfizmu


Polimorfizm to zamierzone dziaanie w idei programowania obiektowego. Zapewnia
ono wielopostaciowo dziaania zalen od wykorzystywanego obiektu. Dokadnie
opisaem to w poprzednim rozdziale. Ponadto wspominaem ju o tym zarwno przy
opisywaniu dziedziczenia, jak i przykrywania pl i metod. Omin wic rozwaania
teoretyczne, a przedstawi tylko efekt dziaania polimorfizmu. Do prezentacji wykorzystam dwie klasy o definicji podanej na listingu 2.42.
Listing 2.42. Klasy dziedziczce z pokrytymi metodami
class A {
public void info1() {
System.err.println("klasa A(1)");
}
public void info2() {
System.err.println("klasa A(2)");
info3();
}
public void info3() {
System.err.println("klasa A(3)");
}
}
class B extends A {
public void info1() {
System.err.println("klasa B(1)");
}
public void info3() {
System.err.println("klasa B(3)");
}
}

Efekty dziaania polimorfizmu bd mg zaobserwowa dziki apletowi przedstawionemu na listingu 2.43.


Listing 2.43. Uycie klas z pokrytymi metodami
public class Applet2 extends Applet {
public void init() {
A a = new A();
a.info1();
a.info2();
a = new B(); // a staje si klasy B
a.info1();
a.info2();
}
}

Na konsoli Javy przegldarki internetowej pojawi si cig napisw zaprezentowany


na rysunku 2.5.

Rozdzia 2. Klasy i obiekty w Javie


Rysunek 2.5.
Wydruk generowany
przez listing 2.43
z uyciem klas
z listingu 2.42

63
klasa
klasa
klasa
klasa
klasa
klasa

A(1)
A(2)
A(3)
B(1)
A(2)
B(3)

Naley zwrci uwag na nastpujce sprawy:


t Wywoywana jest metoda info1 zawsze tej samej klasy, jakiego typu
jest obiekt w danym momencie przechowywany w zmiennej a. Dzieje si
tak mimo tego, e typ zmiennej a to A. Tak wic odwoanie dotyczy

rzeczywistego typu obiektu, a nie wymienionego w referencji.


t Moemy wywoa metod info2 obiektu typu B, mimo e nie zostaa ona

w nim zaimplementowana. Oznacza to, e metoda ta zostaa odziedziczona


po klasie A i jest traktowana jak wasna metoda obiektu B. Jakkolwiek jej
wywoanie nie jest polimorficzne, w przypadku dalszego dziedziczenia
i pokrycia jej moe powsta ten efekt.

t Metoda info3, jakkolwiek wywoywana z metody zaimplementowanej tylko


w klasie A, rwnie pochodzi z tej klasy, ktrej typ reprezentuje obiekt.
Tak wic tworzc klas A, moemy przewidzie uycie nieistniejcej jeszcze

metody z klasy pochodnej, ktra zostanie utworzona dopiero w przyszoci.


Przypominam, e inny przykad dziaania polimorfizmu pokazany zosta wczeniej
w paragrafie 2.1.11. Kolejno inicjacji klas. Problemy zwizane z polimorfizmem
i klasami wewntrznymi omwione s te w paragrafie 2.3.2. Polimorfizm i zmienne
klasy zawierajcej.
Omawiajc efekt polimorfizmu, warto te wspomnie, e niektrzy autorzy pod pojcie
polimorfizmu podcigaj moliwo przeciania metod. Wydaje mi si to zbyt rozszerzon interpretacj. Metody przecione to zazwyczaj takie, ktre dziaaj w bardzo podobny sposb, tylko przekazywanie do nich parametry s innego rodzaju bd
wykorzystuje si domylne. Ponadto istnieje wiele jzykw programowania, ktre nie
udostpniaj przecienia metod, i nikt nie zwraca uwagi na to, e ich polimorfizm
jest zuboony. Wedug mnie przecianie nie naley do zakresu polimorfizmu, ale
zwracam uwag na to, e moesz zetkn si z tak tez.

2.3. Klasy wewntrzne i lokalne


W klasycznym podejciu kada klasa w Javie zawarta jest w osobnym pliku albo stanowi odrbny, atwy do wydzielenia fragment wikszego. Dziki temu klasy mog
tworzy biblioteki dostpne z dowolnego miejsca w caym programie. Od reguy tej
istniej pewne wyjtki wprowadzone w celu podniesienia stopnia hermetyzacji programu. Wyjtkami tymi s klasy wewntrzne i lokalne. Klasa wewntrzna to zdefiniowana w miejscu, w ktrym moe wystpi definicja pola lub metody. Musi wic
ona wystpi midzy pierwszym i ostatnim nawiasem klamrowym ograniczajcym ciao

64

Java. Programowanie obiektowe

klasy na prawach rwnych polu lub metodzie. Klasa, w ktrej definiowana jest klasa
wewntrzna, nazywana jest zawierajc. Klasy lokalne to klasy zdefiniowane w bloku
programu Javy. Ta kwestia moe wic dotyczy inicjatora klasy, inicjatora obiektu,
konstruktora bd (najczciej) metody. Klasa lokalna moe odwoywa si do wszystkich
zmiennych widocznych w miejscu wystpienia jej definicji. Jest ona widoczna i moe
zosta uyta tylko w bloku, w ktrym zostaa zdefiniowana. Poza tymi cechami charakterystycznymi klasy wewntrzne i lokalne s najzwyklejszymi klasami. Mona je
tworzy przy uyciu regu obowizujcych wobec zwykych klas. Gwne zalety to
moliwo ukrywania nazw klas w strukturze bibliotek i pakietw Javy (poza szczeglnymi sposobami uycia s one niedostpne z zewntrz) oraz uywania zmiennych
lokalnych w tych klasach. Daje to czasami moliwo lepszej optymalizacji niektrych fragmentw kodu zarwno ze wzgldu na uatwienia w implementacji algorytmu, jak i pracy kompilatora. Ponadto udostpnia mechanizm zbliony do typu proceduralnego, ktry jest dostpny w wikszoci obiektowych jzykw programowania.
Przykad pokazujcy umiejscowienie klasy wewntrznej i lokalnej pokazany jest na
listingu 2.44.
Listing 2.44. Przykad klasy wewntrznej i lokalnej
class Zawierajaca {
Wewnetrzna w = new Wewnetrzna();
class Wewnetrzna {
// ciao klasy wewntrznej
}
public void metodaZ() {
Lokalna l = new Lokalna();
class Lokalna {
// ciao klasy lokalnej
}
// ciao metody MetodaZ
}
// ciao klasy zawierajcej
}

Mimo tego, e klasy te s penoprawne pod wzgldem konstrukcyjnym, sugeruje si,


aby nie byy one zbyt rozbudowane. Wynika to przede wszystkim z chci uniknicia
pomyek typu: ktry fragment jest metod klasy zawierajcej, ktry wewntrznej,
a ktry lokalnej. Oczywicie moemy jednak tworzy w ten sposb nawet bardzo
skomplikowane konstrukcje formalnie nie istniej bowiem adne ograniczenia w budowaniu klas wewntrznych i lokalnych.
Kompilacja kodu utworzonego na podstawie szablonu pokazanego powyej spowoduje powstanie plikw:
Zawierajaca.class
Zawierajaca$Wewnetrzna.class
Zawierajaca$Lokalna.class

Tak wic zastosowanie klas wewntrznych zmniejszy tylko liczb plikw rdowych.
Liczba plikw skompilowanych class pozostaje staa.

Rozdzia 2. Klasy i obiekty w Javie

65

2.3.1. Dostp do zmiennych klasy zawierajcej


Jakkolwiek oglne zasady tworzenia klas wewntrznych i lokalnych s takie same,
tak jak dla zwykych klas istnieje kilka szczegw, na ktre naley zwrci uwag,
bo rozszerzaj moliwoci udostpnione w czasie tworzenia tych klas. Jednym z takich udogodnie jest bezporedni dostp przez klasy wewntrzne i lokalne do pl klas
zawierajcych. Umoliwia to uproszczenie niektrych konstrukcji i przyblienie ich
do natury programowania strukturalnego. Kilkakrotnie zwracaem ju uwag na to, e
Java w niektrych przypadkach bywa ortodoksyjnie obiektowa. Stosowanie klas wewntrznych nieznacznie agodzi te restrykcje. Warto jednak pamita, e bezporedni
dostp do zmiennych spoza klasy jest niezgodny z ide programowania obiektowego.
Jeli jednak zaoymy, e klasy lokalne powstaj wycznie na potrzeby klasy zawierajcej, w ktrej s potem uywane, moemy przyj, e nie amie to zbyt mocno regu hermetyzacji. Przykad uycia pl przez klasy wewntrzne i lokalne pokazany jest
na listingu 2.45, we fragmencie wikszej klasy.
Listing 2.45. Uywanie pl klasy zawierajcej przez klasy wewntrzne i lokalne
int i;
class Wewnetrzna {
double wynik() { return (i+0.01) * 0.99; }
}
void button_actionPerformed(ActionEvent e) {
class Lokalna {
double wynik() { return (i+0.05) * 0. ; }
}
Lokalna l = new Lokalna();
Wewnetrzna w = new Wewnetrzna();
for (i=0; i<1000; i++){
showStatus("w: " + l.wynik() + ", " + w.wynik());
}

Rozwizanie takie ma midzy innymi t zalet, e nie ma koniecznoci przekazywania czy synchronizowania wartoci pola klasy zawierajcej z dziaaniami klasy wewntrznej czy lokalnej. cile koresponduje to z celem tworzenia klas wewntrznych,
ktre z zaoenia maj wykona jakie zadanie wewntrz klasy zawierajcej, czyli
z dostpem do jej pl. Naley jednak zwrci uwag na niebezpieczestwa mogce
si pojawi w przypadku czciowego odwoywania si do pl klasy zawierajcej
w przypadku istnienia wikszej liczby egzemplarzy klas wewntrznych tego samego
typu. Przykad niebezpiecznych interakcji pokazano na listingu 2.46.
Listing 2.46. Bdne uycie pl klasy zawierajcej
int i;
class Wewnetrzna {
int j;
void setSth(int a) {
i = a;
j = a;
}

66

Java. Programowanie obiektowe

int suma() { return i+j; }

void metodaX() {
int wynik;
Wewnetrzna w = new Wewnetrzna();
Wewnetrzna w2 = new Wewnetrzna();
w.setSth(10);
w2.setSth(100);
wynik = w.suma(); // 110,
// cho spodziewalimy si 20
wynik = w2.suma(); // 200
}

Gdyby w klasie Wewnetrzna nie byo interakcji z polem klasy zewntrznej, wtedy dziaanie tego kodu byoby zupenie inne, ni jest. Takie bdy trudno wyledzi. W zwizku
z tym sugeruj jawne odwoywanie si do pl klas zewntrznych wycznie w przypadku, gdy mamy pewno, e bdziemy uywa wycznie jednego egzemplarza
klasy wewntrznej.

2.3.2. Polimorfizm i zmienne klasy zawierajcej


Uywanie pl klasy zawierajcej powinno odbywa si z du ostronoci w przypadku, gdy klasa wewntrzna dziedziczy po tak zwanej normalnej klasie. Poniej przedstawiony jest przykad, ktry mimo tego, e bezbdnie przechodzi kompilacj (nawet
z uyciem kompilatora jikes i jego opcji pedantycznej kompilacji +P), nie pracuje poprawnie. Najwaniejsze fragmenty, na ktre naley zwrci uwag, wytuciem na listingu 2.47.
Listing 2.47. Bdne uycie pl klasy zawierajcej
import java.applet.*;
public class Aaa extends Applet {
public Integer p1 = new Integer(2p;
public void init() {
System.out.println("wewnatrz konstruktora apletu");
B b = new B();
}
private class B extends A {
public void doSth() {
System.out.println("p1=" + p1p;
}
}
}
abstract class A {
public A(p b
System.out.println("wewnatrz konstruktora A"p;
doSth(p;
}
abstract public void doSth();
}

Rozdzia 2. Klasy i obiekty w Javie

67

Wewntrzna klasa B korzysta z pola p1 pozornie w sposb poprawny. Pozornie, gdy


jeli cofniesz si do paragrafu 2.1.11. Kolejno inicjacji klas, przypomnisz sobie
zapewne, e zanim zostanie zainicjowana klasa B, wczeniej inicjowana jest A. W czasie jej inicjacji w jej konstruktorze wywoywana jest metoda doSth. A metoda ta,
zgodnie z zasadami polimorfizmu, zostanie zaczerpnita ju z klasy B. Jednak nie stanie si to w obszarze wewntrznym apletu Aaa, lecz poza nim. I efektem dziaania bdzie bd (konsola Javy z Internet Explorera) pokazany na rysunku 2.6.
Rysunek 2.6.
Efekt dziaania
programu 2.47
w Internet Explorerze

wewnatrz konstruktora apletu


wewnatrz konstruktora A
java.lang.NullPointerException
at aaa$B.doSth (aaa.java:11)
at A.<init> (aaa.java:20)
at aaa$B.<init> (aaa.java:9)
at aaa.init (aaa.java: )
at com/ms/applet/AppletPanel.securedCall0 (AppletPanel.java)
at com/ms/applet/AppletPanel.securedCall (AppletPanel.java)
at com/ms/applet/AppletPanel.processSentEvent
(AppletPanel.java)
at com/ms/applet/AppletPanel.processSentEvent
(AppletPanel.java)
at com/ms/applet/AppletPanel.run (AppletPanel.java)
at java/lang/Thread.run (Thread.java)

Opera (a w zasadzie jej konsola Javy) pokae ten bd nieco inaczej, co zaprezentowane jest na rysunku 2.7.
Rysunek 2.7.
Efekt dziaania
programu 2.47
w Operze

wewnatrz konstruktora apletu


wewnatrz konstruktora A
java.lang.NullPointerException
at aaa$B.doSth(aaa.java:11)
at A.<init>(aaa.java:19)
at aaa$B.<init>(aaa.java:9)
at aaa.init(aaa.java: )
at opera.PluginPanel.run(opera/PluginPanel.java:30 )
at java.lang.Thread.run(Unknown Source)

Przyczyny bdu lepiej widoczne s po dekompilacji przedstawionego programu z uyciem dekompilatora jad (naley uy opcji noinner). Przedstawiony wczeniej kod
zosta przetumaczony nieco inaczej ni wygld rda (pominem kod klasy A, ktry
jest dokadnie taki sam jak w oryginale). Wynika to z jawnego wyniesienia klasy wewntrznej na zewntrz. Na listingu 2.48 pokazany jest sposb, w jaki widzi ten kod
maszyna Javy.
Listing 2.48. Kod 2.47 po kompilacji i dekompilacji
import java.applet.Applet;
import java.io.PrintStream;
public class Aaa extends Applet {
public void init() {
System.out.println("wewntrz konstruktora apletu");
Aaa$B aaa$b = new Aaa$B(this);
}

68

Java. Programowanie obiektowe

public Aaa() {
p1 = new Integer(2);
}
public Integer p1;

class Aaa$B extends A {


public void doSth() {
System.out.println("p1=" + this$0.p1);
}
Aaa$B(Aaa aaa1){
this$0 = aaa1;
}
private final Aaa this$0; /* synthetic field */
}

Jak wida, wewntrz klasy B dodane jest pole this$0, ktre przechowuje wskazanie
do uywajcego jej obiektu. Wskazanie to jest inicjowane w konstruktorze. Jak wida, zarwno konstruktor, jak i inicjacja klasy odbywa si inaczej, ni jest to jawnie
zapisane. Jeli przypomnimy sobie paragraf 2.1.11. Kolejno inicjacji klas, jasne
si stanie, dlaczego pojawia si bd. W czasie tworzenia obiektu b klasy B, czyli w czasie wykonania wiersza:
B b = new B();

JVM rozpoczyna wykonywanie konstruktora B (w kodzie dekompilowanym Aaa$B).


W ramach wykonania tego konstruktora przed wykonaniem jego pierwszego wiersza,
czyli przed wykonaniem kodu:
this$0 = aaa1;

uruchamiany jest konstruktor klasy A. W konstruktorze tym uruchamiana jest metoda


doSth, w ramach ktrej (w zwizku z polimorfizmem metod) wykonywany jest
wiersz:
System.out.println("p1=" + this$0.p1);

Oczywicie pole p1 apletu Aaa jest ju zainicjowane. Ale pole this$0 obiektu b klasy
B jeszcze nie. W zwizku z tym naturalne jest pojawienie si wyjtku NullPointerException. Oczywicie problemowi temu mona zapobiec, przekazujc kaskadowo do
klasy nadrzdnej warto tego parametru. W praktyce jednak wida, e w takim przypadku nie powinno si uywa klasy wewntrznej. W kocu zostaa ona wprowadzona generalnie w celu rozwizywania problemw, ktre wymagaj tworzenia maych
klas na potrzeby jednorazowego uycia. Przypadek, kiedy uywamy zagniedonego
dziedziczenia, raczej powinno si zrealizowa z uyciem klasycznego rozwizania,
czyli klasycznego tworzenia klas prywatnych.

2.3.3. Zmienne lokalne w klasie lokalnej


Powysze rozwaania dotyczyy zarwno klas wewntrznych, jak i lokalnych. Dla klas
lokalnych istnieje dodatkowa moliwo korzystania ze zmiennych lokalnych i parametrw przekazywanych do wntrza metod. Jednak dostp do tych zmiennych wymaga

Rozdzia 2. Klasy i obiekty w Javie

69

specyficznego ich deklarowania, to znaczy musz one posiada status finalny (dokadne wytumaczenie znaczenia tego statusu znajdziesz w podrozdziale 2.9. Modyfikatory). Przykad uycia zmiennej przekazywanej przez parametr pokazany jest na
listingu 2.49.
Listing 2.49. Przekazywanie zmiennej przez parametr
void showInfo(final int i) {
class Lokalna {
int wynik() { return 2*i; }
}
Lokalna l = new Lokalna();
showStatus("wynik: " + l.Wynik());
}

Jeli na zmiennej musimy wykonywa jakie obliczenia, naley zastosowa inne rozwizanie, a mianowicie wycznie na potrzeby klasy lokalnej musimy zadeklarowa
zmienn finaln, tak jak pokazaem to na listingu 2.50.
Listing 2.50. Uywanie zmiennej finalnej
void showInfo() {
final int i2;
int i = 100;
// tu dziaania na i
class Lokalna {
int wynik() { return 2*i2; }
}
i2 = i;
Lokalna l = new Lokalna();
showStatus("wynik: " + l.Wynik());
}

Przypisanie wartoci zmiennej finalnej musi odby si przed utworzeniem egzemplarza klasy lokalnej, gdy wykorzystuje ona t zmienn w momencie tworzenia egzemplarza klasy, a nie jak nam si wydaje w chwili uycia metody wynik, ktra t zmienn
wykorzystuje. Szerzej na ten temat napisz w rozdziale dotyczcym programowania
sterowanego zdarzeniami, w podrozdziale 4.5. Zdarzenia z parametrem.

2.3.4. this w klasach wewntrznych


Podobnie jak w innych klasach rwnie w wewntrznych i lokalnych z powodzeniem
mona uywa sowa kluczowego this, ktre suy jako referencja do wasnej klasy
macierzystej. Jednak this w klasach zagniedonych nie jest tak bardzo jednoznaczne,
jak w zwykych. W zwizku z tym moliwe jest poprzedzenie sowa this nazw klasy
i oddzielenie jej od niego kropk. Na listingu 2.51 pokazany jest przykad uycia this
w stosunku do klasy zawierajcej.

70

Java. Programowanie obiektowe

Listing 2.51. Uycie this w stosunku do klasy zawierajcej


class SingApplet extends Applet {
int i = 100;
class Wewnetrzna {
int i = 222;
void setValue(int i) {
SingApplet.this.i = i;
}
int wynik() {
return SingApplet.this.i;
}
}
// ...
}

Na listingu 2.52 sowo this zostao uyte w stosunku do klasy wewntrznej.


Listing 2.52. Uycie this w stosunku do klasy wewntrznej
int i = 100;
class Wewnetrzna {
int i = 222;
void setValue(int i) {
Wewnetrzna.this.i = i;
}
int wynik() {
return Wewnetrzna.this.i;
}
}

Kod ten jest rwnowany zapisowi bez adnej referencji przed this pokazanej na listingu 2.53.
Listing 2.53. Oszczdna wersja programu 2.52
int i = 100;
class Lokalna {
int i = 222;
void setValue(int i) {
this.i = i;
}
int wynik() {
return i;
}
}

Wynika to ze sposobu poszukiwania i ustalania przez kompilator nazw pl i metod.


W pierwszej kolejnoci poszukuje on nazw lokalnych (deklarowanych wewntrz
metod), nastpnie (jeli nie znalaz waciwej nazwy) rozszerza zakres poszukiwa, by
w drugim podejciu sprawdzi (w naszym przykadzie) klas lokaln. Jako e tam
znajduje odpowiednie pole, jednoznacznie je identyfikuje. Mimo takiej jednoznacznej
identyfikacji dobr praktyk jest (jeli ju musimy powiela nazwy) stosowanie penych referencji do nazwy, co zapobiega przypadkowym pomykom.

Rozdzia 2. Klasy i obiekty w Javie

71

2.3.5. Korzystanie z klas wewntrznych


Klasy wewntrzne i lokalne to, jak wczeniej pisaem, klasy o wasnociach niemal
niernicych si od zwykych klas. W zwizku z tym klasyczny sposb ich uycia jest
dokadnie taki sam, jak pokazany wczeniej i dotyczcy zwykych klas. Dla przykadu,
uycie klasy lokalnej mona przeprowadzi w sposb pokazany na listingu 2.54.
Listing 2.54. Uycie klasy lokalnej
public void metodaZKlasa() {
class Lokalna {
int wynikLokalny() {
return 0;
}
}
Lokalna l = new Lokalna();
int i = l.wynikLokalny();
//...
}

Mimo tego, e klasy wewntrzne projektowane s z myl o uywaniu ich wewntrz


innych klas, czasami moe okaza si, e musimy wykorzysta je na zewntrz, poza
klasami, wewntrz ktrych umieszczony zosta ich kod. Pomijam przypadek, gdy kod
klasy wewntrznej da si w atwy sposb wykopiowa z zewntrznej i uy w sposb
samodzielny. Jeli jednak korzystalimy z peni moliwoci dostarczonych przez mechanizm zagniedania klas, operacja taka moe by niemoliwa do zrealizowania.
W takim przypadku klasy wewntrznej moemy uy w specyficzny sposb, traktujc
klas zawierajc podobnie do biblioteki, w ktrej znajduje si nasza klasa. Aby utworzy egzemplarz klasy wewntrznej, musimy najpierw utworzy egzemplarz zawierajcej. Dla przykadu posu si najprostszymi klasami o postaci:
class A {
class A1 { }
}

Uycie wewntrznej klasy A1 wymaga utworzenia wczeniej egzemplarza klasy zawierajcej A:


// utworzenie egzemplarza klasy zawierajcej:
A a = new A();
// utworzenie egzemplarza klasy wewntrznej:
A.A1 a1 = a.new A1();

bd w formie skrconej:
A.A1 a1 = (new A()).new A1();

Warto zauway dziwn sytuacj, a mianowicie typ klasy wewntrznej jest widziany
poprzez referencje nazwy klasy zawierajcej i kropki. Natomiast uycie samej klasy
wewntrznej jest niemoliwe. Bardzo podobna sytuacja wystpi w przypadku prby
dziedziczenia. Wykorzystam wprowadzon klas A1 zadeklarowan wewntrz A do
prby dziedziczenia:
class B extends A.A1 {
B(A a) { a.super(); }
}

72

Java. Programowanie obiektowe

Wycznie tak zadeklarowany konstruktor klasy B zostanie zaakceptowany przez


kompilator. Wyjanienie wymaga przypomnienia sobie tego, co napisaem w podrozdziale 2.1.10. Inicjator klasy i obiektu oraz 2.1.11. Kolejno inicjacji klas. Ot
przed utworzeniem klasy przeprowadzane jest budowanie wszystkich klas nadrzdnych z caego acucha dziedziczenia. W zwizku z tym, e do utworzenia egzemplarza klasy wewntrznej potrzebny jest istniejcy egzemplarz klasy zewntrznej, wywoanie konstruktora klasy bazowej moe si odby jedynie w odniesieniu do tego
egzemplarza. Std konieczno wczeniejszego utworzenia klasy zewntrznej i podanie jej jako parametru konstruktora klasy dziedziczcej po wewntrznej. Na skutek
tego korzystanie z klasy dziedziczcej po wewntrznej bdzie musiao mie posta:
// utworzenie egzemplarza klasy zawierajcej
A a = new A();
// utworzenie egzemplarza klasy dziedziczcej
B b = new B(a);

lub w formie skrconej:


B b = new B(new A());

Jeli uylimy penej formy inicjacji klasy wewntrznej bd dziedziczcej po wewntrznej, wtedy po jej uyciu moemy zwolni nazw klasy zewntrznej bez adnych negatywnych konsekwencji:
A a = new A();
A.A1 a1 = a.new A1();
B b = new B(a);
a = null;

Konstrukcja taka nie spowoduje bdw w pracy programu, nawet jeli klasa wewntrzna odwoywaa si w bezporedni sposb do pl klasy zawierajcej. Przyczyn
naley si doszukiwa w sposobie korzystania z klas wewntrznych. W specyfikacji
do Javy 1.1, w ktrej po raz pierwszy wprowadzono klasy wewntrzne, znalazem informacje, e kompilator tumaczy kod rdowy zawierajcy klasy wewntrzne w taki
sposb, aby kod wynikowy nie rni si od kodu zapisanego z uyciem zwykych
(rozcznych) klas. Klasa wewntrzna zawiera niejawn referencj do obiektu klasy
zawierajcej, ktry stanowi jego otoczk. Tak wic nawet jawne zwolnienie obiektu
otaczajcego nie spowoduje fizycznego usunicia obiektu, gdy referencje do niego
przechowuje sam obiekt klasy wewntrznej. Ponadto wedug tej samej specyfikacji
program napisany z uyciem klas wewntrznych, zawierajcy poza tym wycznie
konstrukcje jzykowe charakterystyczne dla Javy 1.0 moe zosta uruchomiony w rodowisku JVM 1.0. Informacja ta jest o tyle wiarygodna, e wikszo pocztkowych
wersji jzykw obiektowych bazujcych na jzykach strukturalnych (dotyczy to przede
wszystkim C++) w czasie kompilacji tumaczona bya najpierw z kodu obiektowego
na strukturalny na poziomie rda, a nastpnie kompilowana zwykym, strukturalnym
kompilatorem. Trudno powiedzie, o ile zmieni si ten mechanizm obecnie. Biorc
jednak pod uwag, e kod programu skompilowany z uyciem rnych kompilatorw
zgodnych z wersj 1.4 jest bezproblemowo wykonywany w przegldarkach internetowych zawierajcych rne wersje Javy 1.1 (oczywicie pod warunkiem e nie zawiera konstrukcji i bibliotek z wyszych wersji), mona powiedzie, e sytuacja zmienia
si niewiele lub wcale.

Rozdzia 2. Klasy i obiekty w Javie

73

2.4. Interfejsy
Jak ju wczeniej wspominaem, Java nie udostpnia mechanizmu wielokrotnego
dziedziczenia. Ze wzgldu na brak nieobiektowych elementw takie rozwizanie skutkowaoby sporymi utrudnieniami w tworzeniu bardziej zaawansowanych programw.
Skutkowaoby, gdyby nie interfejsy. Jest to specjalnie zaprojektowany mechanizm,
ktry umoliwia klasom wykorzystanie innych klas, nawet jeli byy one nieznane
w czasie tworzenia fragmentw wykorzystujcego je kodu. Analogicznie do sprztowego interfejsu ten z Javy umoliwia czenie ze sob klas za pomoc struktury poredniczcej stworzonej niezalenie od czonych klas. Interfejsy sprawdzaj si wszdzie
tam, gdzie istnieje czasowa rozbieno pomidzy powstaniem klasy uywajcej
pewnych obiektw, a powstaniem tej, ktra bdzie uywana. Tworzc na przykad taki mechanizm w duym zespole programistycznym, musimy zadba o waciwy obieg
informacji i dostarczenie penego opisu oczekiwa. Musielibymy przedstawi specyfikacj uywanej przez nas klasy w postaci:
Musi posiada pola o nastpujcych nazwach i typach, musi posiada metody
o nastpujcych nazwach i typach oraz formalnej licie parametrw oraz musi
dziedziczy wasnoci po konkretnej klasie.
Zamiast pisa to wszystko, wystarczy, e podamy:
Musi implementowa interfejs XXX.
I sprawa jest oczywista. Nie grozi nam adne przekamanie w nazewnictwie pl czy
metod. Interfejs jest dostarczany razem z nasz klas i to my jestemy odpowiedzialni
za jego ksztat. Kompilator nie dopuci do powstania bdu. Ponadto interfejs ma t
zalet, e moe by wykorzystany w czasie testowania programu nawet wtedy, gdy
waciwa klasa, ktrej bdziemy uywa w przyszoci, jeszcze nie powstaa. Dodatkowo korzystajc z zalet interfejsu, uwalniamy autora klasy uywanej przez nas od
ograniczenia typu twoja klasa musi dziedziczy wasnoci po klasie YYY. Nie ma potrzeby stosowa tego ograniczenia. Cakowit zgodno typw zapewnia wanie interfejs, bez wzgldu na to, jak klas nadrzdn wybierze uytkownik. Dziki temu
do mechanizmu obsugi zdarze jako obiekt nasuchujcy moe by przekazany zarwno obiekt typu Applet, jak i Button, mimo e oba nale do rnych acuchw
dziedziczenia. A wszystko dziki temu, e implementuj waciwy interfejs (w peniejszym zrozumieniu idei interfejsw moe pomc przestudiowanie rozdziau 4.
Programowanie sterowane zdarzeniami). Ponadto dziki interfejsowi moemy na
przykad doda klasy zakupione od jednego producenta do mechanizmu ich wykorzystania zakupionego gdzie indziej, nawet jeli obie firmy nie wiedziay o swoim istnieniu
(nie mwic o tym, e na pewno nie znay struktury i dziaania swoich produktw).
Poza obsug zdarze interfejsy s uywane w sposb systemowy w programowaniu
wielowtkowym (patrz podrozdzia 4.2. Klasyczna obsuga zdarze).

74

Java. Programowanie obiektowe

2.4.1. Definicja interfejsu


Oglna posta deklaracji interfejsu jest bardzo podobna do deklaracji klasy i jest pokazana na listingu 2.55.
Listing 2.55. Szablon deklaracji interfejsu
interface Nazwa {
final typ nazwa_zmiennej_finalnej_1;
...
final typ nazwa_zmiennej_finalnej_K;
typ nazwa_metody_1([lista_parametrw]);
...
typ nazwa_metody_L([lista_parametrw]);
}

Gwna rnica w stosunku do klas to:


t Brak ciaa metod deklarowanych w interfejsie po nazwie metody zamiast

bloku instrukcji ujtego w nawiasy klamrowe znajduje si rednik.

t Brak konstruktora, czyli specjalizowanej metody uywanej w przypadku

tworzenia egzemplarza interfejsu (oczywicie gdyby byo to moliwe,


gdy jak wspominaem, interfejs nie moe by wzorcem do powstania
egzemplarza).

t Moliwo stosowania wycznie zmiennych finalnych, czyli odpowiednikw

staych z innych jzykw.

Przykadowy interfejs o nazwie Przekaznik, ktry zawiera jedn metod wykonajZestawInstrukcji z argumentem typu cig tekstowy pokazany jest poniej.
interface Przekaznik {
void wykonajZestawInstrukcji(String instrukcje);
}

2.4.2. Implementacje
Jak wczeniej wspominaem, sam interfejs z punktu widzenia metod jest tylko deklaracj ich wystpienia. Samo ciao metody musi zosta zaimplementowane w innym
miejscu. Wspominaem rwnie, e sam interfejs nie moe by miejscem tej implementacji. Podobnie jak wirus musi si on doklei do klasy, aby by w peni funkcjonalny. Takie doklejanie odbywa si z uyciem sowa kluczowego implements. Po
dodaniu tego fragmentu mog wreszcie na listingu 2.56 zaprezentowa peny format
nagwka definicji klasy.
Listing 2.56. Peny format nagwka klasy
class Nazwa [extends NazwaNadklasy]
[implements Interfejs1 [, Interfejs2 [...]]]
{
public typ metoda_z_interfejsu([parametry]) {

Rozdzia 2. Klasy i obiekty w Javie

75

ciaco_implementowanej_metody
}
// cz gwna klasy
// wedug wczeniejszego schematu
}

Ju wskazuje pobiena analiza nagwka, klasa moe implementowa wiksz liczb


interfejsw. W czci gwnej klasy musi znale si deklaracja i implementacja metody, ktrej istnienie jest zadeklarowane w interfejsie (z wyjtkiem przypadku, kiedy
klas deklarujemy jako abstrakcyjn). Naley pamita, e do ciaa klasy naley doda
metody zadeklarowane w implementowanych interfejsach. Metody te musz by deklarowane z modyfikatorem public. Przykadowa implementacja interfejsu przekaznik
zadeklarowanego wczeniej z uyciem klasy UrzadzenieZdalnieSterowane bdzie miaa
posta pokazan na listingu 2.57.
Listing 2.57. Przykadowa implementacja interfejsu
class UrzadzenieZdalnieSterowane
extends Urzadzenie implements Przekaznik {
private int dekodujRozkaz(String instrukcje, int polozenie) {
// tu dekodowanie instrukcji
// o numerze polozenie na Rozkaz typu int
}
private int dekodujParametr(String instrukcje, int polozenie) {
// tu dekodowanie parametru o numerze polozenie
// z cigu tekstowego na typ int
}
private void wykonajRozkaz(int rozkaz, int parametr) {
// tu wykonanie instrukcji rozkaz
// z parametrem parametr
}
public void WykonajpestawInstrukcji(String instrukcjep b
int n = 0;
int r, p;
r = dekodujRozkaz(instrukcje, np;
p = dekodujParametr(instrukcje, np;
while (r>0p b
wykonajRozkaz(r, pp;
n++;
r = dekodujRozkaz(instrukcje, np;
p = dekodujParametr(instrukcje, np;
}
}
}

Na listingu 2.57 wytuszczona zostaa metoda wykonajZestawInstrukcji pochodzca


z interfejsu Przekaznik. Mona te zauway, e poza dekodujRozkaz, dekodujParametr
i wykonajRozkaz klasa nie zawiera adnych innych metod charakterystycznych dla
samej klasy UrzadzenieZdalnieSterowane.

76

Java. Programowanie obiektowe

Stosujc interfejsy, naley pamita o mogcym pojawi si problemie wynikajcym


z konfliktu nazw metod. Jakkolwiek Java umoliwia przecianie metod, moe si
zdarzy, e interfejsy implementowane w danej klasie dostarczaj metody o tej samej
nazwie, tym samym zestawie parametrw i rnym wyniku. Kompilator nie jest w stanie
obsuy takiego przecienia metod, wic generuje bd semantyki jzyka. Problem
ten szerzej opisaem w paragrafie 2.4.6. Dziedziczenie interfejsw.

2.4.3. Zastosowanie interfejsw


Wyobramy sobie, e tworzymy oprogramowanie do zarzdzania inteligentnym budynkiem. Inwestor zakupi do tego budynku bardzo wymylne urzdzenie klimatyzacyjne, do ktrego doczony by sterownik obsugi napisany w Javie. Oczywicie
zgodnie z konwencj jzyka jest to w peni funkcjonalna klasa, ktra udostpnia programicie metody ustawTemperature, ustawWilgotnosc i ustawSileNadmuchu. Klasa ta
jest w peni funkcjonalna, to znaczy moemy uytkownikowi naszego programu udostpni korzystanie z kadej funkcji klimatyzatora, ale tylko w sposb manualny, to
znaczy moe on zmienia tylko jeden parametr w danym momencie i nie moe zada, aby na przykad temperatura zmienia si, ale dopiero za godzin. Nie ma si co
dziwi, w kocu jest to tylko sterownik do fizycznego urzdzenia. Pen funkcjonalno mona uzyska dopiero po wprowadzeniu wasnego, bardziej zaawansowanego
programu. Moglibymy oczywicie utworzy now klas dziedziczc wasnoci po
klasie sterownika klimatyzacji i w jej rozszerzeniu zamieci nowe metody, ktre
umoliwiyby stworzenie programatora zmian. Nie jestemy jednak pocztkujcymi
programistami. Poprzednio wykonywalimy bardzo podobn prac dla maej lokalnej
kotowni. Mamy wic ju opracowan klas, ktra doskonale nadaje si do tworzenia
listy instrukcji typu o tej godzinie mam wykona tak akcj. Projektujc klas EdyorPolecen, przewidzielimy jego przysze wykorzystanie za porednictwem pokazanego
wczeniej interfejsu Przekaznik. Skorzystalimy z moliwoci tworzenia zmiennych
o typie takim jak nazwa interfejsu. Oczywicie nie oznacza to, e jest to egzemplarz
typu interfejs. Jest to egzemplarz dowolnej klasy (implementujcej ten interfejs), ktrej na dodatek nie musimy zna w chwili deklarowania jej uycia. Na listingu 2.58
przedstawiam fragment klasy EdytorPolecen uywajcy klasy implementujcej interfejs Przekaznik.
Listing 2.58. Przykad uycia interfejsu
class EdytorPolecen {
// deklaracja uycia klasy
// implementujcej Przekaznik
Przekaznik p;
// konstruktor klasy
EdytorPolecen(Przekaznik p) {
this.p = p;
}
// metoda pokazujca okno dialogu z uytkownikiem
// oraz zdalnie uruchamiajca urzdzenie
// reprezentowane przez obiekt p
public void showDialog() {
boolean kolejnykrok = true;
String instrukcje;

Rozdzia 2. Klasy i obiekty w Javie

77

while (kolejnykrok) {
// tu odbywa si caa komunikacja z uytkownikiem,
// w tym ustawienie wartoci zmiennej kolejnykrok
// oraz instrukcje
p.WykonajZestawInstrukcji(instrukcje);
}
}

}
// dalsza cz klasy

Jak wida, do zmiennej p odwoujemy si tak, jak do najzwyklejszego obiektu. Jest to


jak najbardziej suszne, gdy jest to obiekt takiego typu, ktry implementuje interfejs
Przekaznik. Oczywicie naley pamita, aby zainicjowa go we waciwy sposb i przekaza go w konstruktorze tworzcym obiekt typu EdytorPolecen. Fragment kodu programu, ktry wykonuje tak akcj, pokazany jest na listingu 2.59 (kod klasy UrzadzenieZdalneSterowane znajduje si wczeniej).
Listing 2.59. Przykad odwoania do obiektu implementujcego interfejs
UrzadzenieZdalneSterowane k;
EdytorPolecen p;
k = new UrzadzenieZdalneSterowane();
p = new EdytorPolecen(p);
p.showDialog();

Jeli odpowiednio dobrze zaprojektowalimy klas EdytorPolecen, moe si okaza,


e nie musimy jej modyfikowa w razie wykorzystania z zupenie nowym, nieznanym
w czasie jej tworzenia urzdzeniem.
Odszukiwanie metod zdefiniowanych w interfejsie odbywa si w sposb dynamiczny,
to znaczy interpreter Javy w czasie napotkania na odwoanie do metody nalecej do
interfejsu przeglda list wszystkich metod obiektu, ktry jest uyty w miejscu wskazania na interfejs. Na skutek takiego odwoywania si do metod ten fragment programu
moe by nawet w znaczny sposb spowolniony. W zwizku z tym nie powinno si
stosowa interfejsw wszdzie tam, gdzie jest to wskazane ze wzgldu na krytyczne
szybkoci wykonania oraz moliwo zastpienia ich klasami.

2.4.4. Stae symboliczne


Interfejsw mona uywa do deklarowania czsto wykorzystywanych wartoci, ktre
w innych jzykach nazywane s staymi. Java nie udostpnia mechanizmu deklarowania staych globalnych podobnego do deklaracji const w Object Pascalu czy instrukcji preprocesora #define w C++. Jednak stosowanie staych symbolicznych w wielu
przypadkach uatwia modyfikowanie programw. Mona da wiele przykadw, w ktrych pewna staa warto determinujca dziaanie algorytmu wystpuje w caym programie kilkadziesit bd kilkaset razy. Gdyby uywa jej jawnie w postaci wartoci
liczbowej, jej zmiana w caym programie mogaby by niezmiernie uciliwa. Naprzeciw temu zapotrzebowaniu wychodz specyficzne moliwoci stosowania interfejsw. Jak wspominaem w trakcie wprowadzania informacji o strukturze interfejsu,
poza deklaracj istnienia metod moe on posiada rwnie pola, ktre maj status

78

Java. Programowanie obiektowe

zmiennych finalnych. Mona wic zadeklarowa stae w podobny sposb, jak dziao
si to w innych jzykach obiektowych, tak jak na listingu 2.60.
Listing 2.60. Deklaracja staych symbolicznych w interfejsie
interface PrzyciskiPl {
String mbYes = "Tak";
String mbNo = "Nie";
String mbCancel = "Anuluj";
}

Ten sam zestaw przyciskw, lecz w wersji angielskiej znajduje si na listingu 2.61.
Listing 2.61. Deklaracja staych symbolicznych w interfejsie
interface PrzyciskiEn {
String mbYes = "Yes";
String mbNo = "No";
String mbCancel = "Cancel";
}

Wykorzystanie staych zadeklarowanych w interfejsie wymaga dodania do obiektu


sowa implements z waciw nazw interfejsu, tak jak na listingu 2.62.
Listing 2.62. Uycie staych symbolicznych
public class DemoApplet extends Applet
implements PrzyciskiPl {
Button buttonYes = new Button();
Button buttonNo = new Button();
Button buttonCancel = new Button();

public void init() {


buttonYes.setLabel(mbYes);
add(button1);
buttonNo.setLabel(mbNo);
add(button2);
buttonCancel.setLabel(mbCancel);
add(button3);
}

Zmiana wersji jzykowej wymaga w tym przykadzie wycznie zmiany nazwy uywanego interfejsu w deklaracji klasy. Aplet z angielsk wersj jzykow przyciskw
wymagaby jedynie deklaracji, co pokazaem na listingu 2.63 poprzez wytuszczenie
zmiany w nagwku.
Listing 2.63. Zmiana jzyka poprzez niewielk modyfikacj nagwka klasy
public class DemoApplet extends Applet
implements PrzyciskiEn {
// ciao dokadnie takie samo
}

Rozdzia 2. Klasy i obiekty w Javie

79

Takie podejcie do staych jest znacznie wygodniejsze od stosowanego w innych jzykach, gdzie wymagana jest fizyczna podmiana wartoci staych, zamiast stosowanej
w Javie podmiany interfejsu, ktrego uywamy do stworzenia klasy. Jeli jednak programista przyzwyczajony jest do klasycznego ukadu stosowania staych w programie, moe to zrobi bez deklarowania implementacji interfejsu w tworzonej klasie,
tak jak na listingu 2.64.
Listing 2.64. Uycie staych symbolicznych bez implementacji interfejsu
interface Interfejs {
int JEDEN = 1;
int DWA = 2;
}
class TestInt {
int i = Interfejs.JEDEN;
}

Takie zastosowanie, pozornie mniej atrakcyjne, ma zalet grupowania staych w pewnego rodzaju kontenery, ktrymi s interfejsy. Mona z tego skorzysta, na przykad
tworzc dwa interfejsy z nazwami miesicy i z liczb dni w miesicu. Oba bd
miay pola o dokadnie takich samych nazwach, lecz rnym typie i znaczeniu. Moe
to w niektrych sytuacjach bardzo uproci kod rdowy:
print(Nazwy.STYCZEN + " ma " + Dni.STYCZEN + " dni");

Jak si mona domyli, interfejs Nazwy deklaruje nazwy miesicy, a Dni liczb
dni w miesicu.

2.4.5. Troch kodu w interfejsie


Wprowadzajc interfejsy, zwracaem uwag na to, e jest to szczeglna konstrukcja,
ktra nie zawiera adnego kodu, a jedynie deklaracje istnienia metod. Nie jest to do
koca prawda, poniewa wewntrz interfejsw mona definiowa klasy statyczne.
Wewntrz tych klas moe znajdowa si do duy kod, a nawet odwoania do metod
innych klas, pod warunkiem e s one statyczne. Tak wic niejako bocznymi drzwiami moemy wprowadzi do interfejsu troch kodu, tak jak w przykadzie zaprezentowanym na listingu 2.65.
Listing 2.65. Przemycanie kodu do interfejsu
import java.applet.*;
interface Interfejs {
class S {
{ System.err.println("static S"); }
S() {
System.err.println("konstruktor S");
}
}
S s = new S();
}

80

Java. Programowanie obiektowe


public class Applet2 extends Applet {
class A implements Interfejs { }
A a1 = new A();
A a2 = new A();
static {
System.err.println("inicjator klasy");
}
{
System.err.println("inicjator obiektu");
}
public Applet2() {
System.err.println("konstruktor obiektu");
}
}

Ten fragment kodu wygeneruje na konsoli Javy w przegldarce komunikaty w kolejnoci pokazanej na rysunku 2.8.
Rysunek 2.8.
Wydruk generowany
przez program 2.65

inicjator klasy
static S
konstruktor S
inicjator obiektu
konstruktor obiektu

Zmiana miejsca implementacji interfejsu, jak to pokazaem na listingu 2.66, bdzie


skutkowaa inn kolejnoci wykonania kodu.
Listing 2.66. Inne umieszczenie kodu w interfejsie
public class Applet2 extends Applet
implements Interfejs{
static {
System.err.println("inicjator klasy");
}
{
System.err.println("inicjator obiektu");
}
public Applet2() {
System.err.println("konstruktor obiektu");
}
}

Efekt dziaania zmiany pokazaem na rysunku 2.9.


Rysunek 2.9.
Wydruk generowany
przez program
z listingu 2.66

static S
konstruktor S
inicjator klasy
inicjator obiektu
konstruktor obiektu

Naley jednak pamita, e zmienne w interfejsach s traktowane jako finalne, tak


wic umieszczony w nich kod bdzie si wykonywa tylko jeden raz w czasie adowania klasy. Jeli klasa implementuje wiksz liczb interfejsw zawierajcych kod,

Rozdzia 2. Klasy i obiekty w Javie

81

to kolejno wykonania kodu bdzie zgodna z kolejnoci wymienionych do implementacji interfejsw. Powysze uycie kodu w interfejsie moe by uyteczne na przykad
jako wywietlanie nazwy naszej biblioteki w sprzedawanym pakiecie.
Innym sposobem wstawienia kodu do interfejsu, ktry moe by wykonany bez jego
implementacji w metodzie, jest wstawienie do niego egzemplarza klasy rozszerzajcego inny interfejs ze zdefiniowanym wewntrz kodem. Przykad takiego amaca
wraz z jego uyciem pokazany jest na listingu 2.67.
Listing 2.67. Kolejny sposb na umieszczenie kodu w interfejsie
import java.applet.*;
interface InsideInt {
interface Method {
int run(int i);
}
Method stub = new Method(p b
public int run(int ip b
System.err.println("Parametr przekazany: " + ip;
return i+1;
}
};
}
public class AppletTst extends Applet
implements InsideInt {

public void init() {


int i;
i = this.stub.run(17p;
i = this.stub.run(ip;
}

Wytuszczony fragment w interfejsie odpowiada za stworzenie metody, ktr bdziemy w przyszoci wykorzystywa, co pokazane jest w aplecie rwnie z uyciem
wytuszczenia. Jak wida, mimo tego e klasa AppletTst implementuje interfejs InsideInt, moemy w niej korzysta z metod w nim zadeklarowanych. Zalet takiego
udziwnionego stosowania kodu jest to, e nie moemy modyfikowa tej metody, a wic
zmienia jej dziaania, ale moemy implementowa rne funkcjonalnoci w jednej
metodzie, co lubi niektrzy programici.

2.4.6. Dziedziczenie interfejsw


Podobnie jak klasy, interfejsy mog podlega dziedziczeniu. Jednak dziedziczenie interfejsw jest bardziej rozbudowane, a mianowicie w procesie tym nie wystpuje ograniczenie co do jednokrotnego dziedziczenia. Tak jak na listingu 2.68 interfejs moe
wic dziedziczy po wikszej liczbie interfejsw.

82

Java. Programowanie obiektowe

Listing 2.68. Dziedziczenie interfejsu po wielu interfejsach


interface Interfejs {
void metoda(int i);
}
interface Interfejs1 {
void metoda1(int i);
}
interface Interfejs2
extends Interfejs, Interfejs1 {
void metoda2(int i);
}

Tak jak w przypadku klasycznego dziedziczenia ostatni w acuchu interfejs, czyli


w naszym przykadzie Interfejs2, posiada wszystkie cechy interfejsw, po ktrych
dziedziczy, to znaczy jego implementacja wymaga uwzgldnienia wszystkich metod
w rwnorzdny sposb, tak jak to pokazaem na listingu 2.69.
Listing 2.69. Implementacja interfejsu o wielu przodkach
import java.applet.*;
public class Applet2 extends Applet
implements Interfejs2 {
public void metoda(int i) {
// ciao metody
}
public void metoda1(int i) {
// ciao metody
}
public void metoda2(int i) {
// ciao metody
}
}

Gdyby okazao si, e w acuchu wielokrotnego dziedziczenia ktra z metod ma


dokadnie tak sam nazw i dokadnie taki sam zestaw parametrw, w obiekcie implementujcym umieszcza si j tylko jeden raz. Problem pojawia si w przypadku,
gdy interfejsy implementowane w danej klasie dostarczaj metody o tej samej nazwie,
tym samym zestawie parametrw i rnym typie wartoci zwracanej. Kompilator nie
jest w stanie stworzy takiego przecienia metody, wic generuje bd semantyki jzyka. Warto jednak zauway, e bd jest generowany dopiero na etapie kompilacji
klasy. Tak wic konstrukcja pokazana na listingu 2.70 bdzie poprawna z punktu widzenia kompilatora, cho cakowicie bezsensowna z punktu widzenia jzyka.
Listing 2.70. Bdne wielokrotne dziedziczenie interfejsw
interface Interfejs {
void metoda(int i);
}
interface Interfejs1 {
int metoda(int i);
}
interface Interfejs2
extends Interfejs, Interfejs1 { }

Rozdzia 2. Klasy i obiekty w Javie

83

Dzieje si tak dlatego, e formalnie rzecz biorc, powyszy zapis jest rwnowany
deklaracji z listingu 2.71.
Listing 2.71. Pozorna posta interfejsu z listingu 2.70
interface Interfejs2 {
void metoda(int i);
int metoda(int i);
}

Kompilator na szczcie tego ju nie zaakceptuje, gdy przecienie z punktu widzenia


typu wyniku nie jest dopuszczalne.

2.4.7. Egzemplarz interfejsu


Porednio wspominaem ju o tym, wprowadzajc ide przywiecajc powstaniu
interfejsw. Przedstawi to teraz dokadnie, zwracajc uwag na konsekwencje tego
faktu. Interfejs moe zosta wykorzystany jako identyfikator typu deklarowanej
zmiennej. Moe to mao powiedziane. Idea uycia interfejsw bazuje wanie na
tym, e w miejscu, gdzie bdziemy potrzebowali uy klasy, ktra bdzie implementowa jaki interfejs jako typ zmiennej, uyjemy interfejsu, a nie nieznanej sobie klasy.
Uycie interfejsu jako typu zmiennej wynika z tego, e nie znamy rzeczywistego typu
klasy, ktr bdziemy wykorzystywa, a moe si te zdarzy, e nie wiemy nawet,
po jakiej klasie ona dziedziczy. Deklarujemy wic zmienn typu interfejs wedug klasycznego wzorca (ActionListener jest nazw interfejsu):
ActionListener lst;

Oczywicie to, e zmienna jest typu zgodnego z interfejsem, nie oznacza, e moemy
stworzy zmienn z uyciem interfejsu. Konstrukcja pokazana poniej, uywajca
interfejsu wykorzystywanego przy tworzeniu obiektw nasuchujcych w AWT jest
bdna i nie da si jej uy.
ActionListener a = new ActionListener();

// bd

Jeli stworzylimy klas, ktra implementuje ten interfejs:


class ALclass extends Button
implements ActionListener {
// ...
}

wtedy dopiero moemy jej uy do stworzenia obiektu:


ActionListener a = new ALclass();

Najczciej jednak w takim przypadku nie tworzymy obiektu od zera z uyciem operatora new, ale odbieramy go od uytkownika kocowego z uyciem parametru jakiej
metody. Moemy zadeklarowa, e metoda ta bdzie przekazywaa obiekt typu interfejs:
void dodajLst(ActionListener lst) {
addActionListener(lst);
}

84

Java. Programowanie obiektowe

W takim przypadku dbaniem o to, czy przekazujemy do tej metody waciwy obiekt,
zajmie si kompilator. Dokadnie w taki sposb ustawiane jest wskazanie na pole
stub w klasie Applet:
private AppletStub stub;
public final void setStub(AppletStub stub) {
this.stub = (AppletStub)stub;
}

W zaprezentowanym przykadzie wystpuje bardzo ciekawa sytuacja. Ot pole stub


przechowuje wskazanie na obiekt implementujcy interfejs AppletStub, ktry znajduje si poza apletem, czyli poza caym programem uruchamianym w rodowisku
przegldarki. Obiekt ten istnieje bezporednio tylko w JVM i poza przechowywanym
wskazaniem nie mamy do niego adnego dostpu (nie jest jawnie tworzony w adnym miejscu programu, ani w adnej czci biblioteki).
Poza scedowaniem na kompilator sprawdzania typu obiektu moemy postpi inaczej
i samodzielnie przej rozpoznanie odbieranego obiektu pod ktem implementacji
konkretnego interfejsu. Naley do tego wykorzysta operator instanceof w sposb
analogiczny jak w przypadku zwykej klasy, na przykad tak jak na listingu 2.72.
Listing 2.72. Sprawdzanie typu interfejsu
void dodajLst(Object lst) {
if (lst instanceof ActionListener) {
addActionListener(lst);
}
if (lst instanceof MouseListener) {
addMouseListener(lst);
}
}

W zaprezentowanym przykadzie typ interfejsu rozpoznawany jest wewntrz metody


dodajLst. Na podstawie tego typu dodawany jest waciwy obiekt obsugi zdarze.
Jeli obiekt nie da si rozpozna jako aden z obiektw nasuchujcych, metoda nie
wykonuje adnej akcji.
Wicej przykadw uywania zmiennych o typie interfejsu znajduje si w rozdziale 4.
Programowanie sterowane zdarzeniami. W zrozumieniu tego problemu pomoe Ci
te paragraf 2.5.2. Jawna klasa anonimowa.

2.5. Klasy anonimowe


Klasy anonimowe s bardzo silnie powizane z procesem tworzenia ich egzemplarzy
(czyli obiektw). Jako e kwestia ta silnie czy ze sob definicj klasy z jej egzemplarzem (czyli obiektem), postanowiem opisa j samodzielnie, nie wczajc tego
problemu ani do podrozdziau opisujcego tworzenie klas, ani obiektw. Klasa anonimowa to penoprawna klasa wewntrzna lub lokalna, niezawierajca nazwy oraz

Rozdzia 2. Klasy i obiekty w Javie

85

konstruktora, ktra posiada jedynie niewielkie ograniczenia w stosunku do zwykej


(nazwanej) klasy. Jednak sens jej stosowania wystpuje wycznie w przypadku, gdy
klasa ma by niewielka, prosta w uyciu oraz stosowana jednorazowo bd w bardzo
ograniczony sposb. Ze wzgldu na ograniczenia formalne nadaje si ona wycznie
do implementacji interfejsw bd reimplementacji metod istniejcych w klasach bazowych. Stosowanie duych i rozbudowanych klas anonimowych oczywicie jest
moliwe, w praktyce jednak znacznie zaciemnia kod rdowy. Jest to raczej w sprzecznoci z ide programowania obiektowego, ktra zakada upraszczanie kodu przez
ukrywanie szczegw implementacyjnych. Stosowanie klas anonimowych nie wpywa
rwnie w aden sposb na wielko czy efektywno kodu wynikowego (czasami
nawet mona poprawi sytuacj, rezygnujc z klas anonimowych, co poka w rozdziale 4. Programowanie sterowane zdarzeniami). Mimo tych zastrzee klasy anonimowe stosuje si do czsto, zwaszcza w mechanizmach obsugi zdarze.

2.5.1. Klasyczne uycie klasy anonimowej


Klasa anonimowa to klasa definiowana w miejscu, w ktrym tworzymy jej egzemplarz. Podobnie jak w przypadku klasycznych obiektw moemy je tworzy w sposb
jawny, tak aby nastpnie byy dostpne przez nazw, bd niejawny, na przykad
w czasie przekazywania ich do dalszego uycia wewntrz innych klas. Najczciej
wykorzystuje si t drug metod, gdy w naturalny sposb czy si ona z cechami
klasy anonimowej. Tworzona jest na jednorazowy uytek za pomoc jednostkowej
definicji, ktra nigdy wicej w tej postaci nie bdzie uywana. Klasa anonimowa jest
tworzona wedug szablonu pokazanego na listingu 2.73.
Listing 2.73. Schemat tworzenia klasy anonimowej
new
KlasaBadzInterfejsBazowy
([lista argumentw])
{
ciaco klasy anonimowej
}

Jak wida, klasa anonimowa moe zosta zdefiniowana wycznie w chwili tworzenia
jej egzemplarza, po wystpieniu operatora new. Po tym operatorze musi wystpi definicja typu, po ktrym dziedziczy klasa anonimowa. Moe to by nazwa klasy bazowej bd interfejsu. Jeli podajemy nazw interfejsu, domylnie oznacza to, e klasa
anonimowa dziedziczy po klasie Object i implementuje wymieniony interfejs. Nie
jest moliwa implementacja wikszej liczby interfejsw ni jeden ani dziedziczenie
po klasie innej ni Object i jednoczesna implementacja interfejsu. Przykad klasycznej definicji klasy anonimowej pokazany jest na listingu 2.74.
Listing 2.74. Klasyczna definicja klasy anonimowej
import java.applet.*;
import java.awt.*;
import java.awt.event.*;

86

Java. Programowanie obiektowe


public class Applet2 extends Applet {
Button b = new Button("przycisk");
public void init() {
b.addActionListener(
new ActionListener(p b
public void actionPerformed(ActionEvent ep b
// obsuga zdarzenia e
}
}
);
add(b, null);
}
}

Wytuszczony fragment to definicja klasy anonimowej dziedziczcej (niejawnie) po


klasie Object i implementujcej interfejs ActionListener. Interfejs ten deklaruje istnienie metody actionPerformed, ktra jest zdefiniowana w pokazanej klasie anonimowej. Klasa ta bdzie wykorzystana w obiekcie typu Button jako klasa nasuchujca
zdarze pochodzcych od przycinitego przycisku ekranowego. W chwili pojawienia
si tego zdarzenia wywoywana bdzie metoda actionPerformed klasy podawanej
w metodzie addActionListener. W innych popularnych jzykach obiektowych, takich
jak Object Pascal czy C++, w takim wypadku przekazywalibymy adres procedury,
ktra byaby wywoywana we waciwym momencie. Java jest tak mocno obiektowa,
e jest to niemoliwe. Zamiast tego przekazuje si adres obiektu, ktry w tym wypadku
jest nienazwanego typu. W zwizku z tym, e takie dziaanie wykonywane jest jednorazowo dla przyspieszenia tworzenia kodu, stosuje si klas anonimow. Konstrukcja
taka nie wpywa na czytelno kodu, jednak przyja si wrd osb uywajcych
Javy. Wicej na temat uycia klasy anonimowej i przykady eliminacji anonimowoci
znajdziesz w rozdziale 4. Programowanie sterowane zdarzeniami. Na listingu 2.75
zaprezentowaem jeszcze jeden przykad uycia klasy anonimowej. Pozornie nie wnosi
on nic nowego poza zaciemnieniem kodu. W praktyce umoliwia wyodrbnienie i zgrupowanie kodu w jeden blok, podobnie jak podprogramy czy procedury lokalne w klasycznym programowaniu strukturalnym.
Listing 2.75. Uycie klasy anonimowej do zgrupowania kodu
(new Object() {
// definicja pl
public void make() {
// dziaania w metodzie make
}
}).make();

Przedstawiona klasa anonimowa gromadzi pewne instrukcje wewntrz metody make,


umoliwiajc dostp do lokalnych pl tej klasy. Stosowania takiej konstrukcji ma sens
w przypadku, gdy chcemy stworzy silniejsz hermetyzacj wewntrz pojedynczej
metody.

Rozdzia 2. Klasy i obiekty w Javie

87

2.5.2. Jawna klasa anonimowa


Najczciej stosuje si klasy anonimowe, ktre nie posiadaj nazwanych egzemplarzy. Nic jednak nie stoi na przeszkodzie temu, aby tworzy klasy anonimowe z ich
uyciem. Fakt, e egzemplarz klasy jest nazwany, nie wpywa oczywicie na anonimowo jej typu, co nie zawsze i nie przez wszystkich jest zrozumiae. W praktyce
wic pokazany na listingu 2.76 przykad rwnie zawiera klas anonimow (wytuszczony fragment jest deklaracj klasy dziedziczcej po Object i implementujcej interfejs ActionListener).
Listing 2.76. Klasa anonimowa o nazwanym egzemplarzu
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Applet2 extends Applet {
Button b = new Button("przycisk");
ActionListener a = new ActionListener(p b
public void actionPerformed(ActionEvent ep b
// obsuga zdarzenia e
}
};
public void init() {
b.addActionListener(a);
add(b, null);
}
}

Pokazany przykad uatwi rozwaania na temat sposobu rozszerzania klas za pomoc


mechanizmu klas anonimowych. Wprowadzajc interfejsy, zwracaem uwag na to,
e moemy stosowa zmienne typu zgodnego z typem interfejsu. Tak wanie stao
si w przykadzie pokazanym na listingu 2.76. Moe on by uyty w miejscu, gdzie
wymagany jest taki typ (na przykad w metodzie addActionListener we wczeniejszym przykadzie), bd jawnie, na przykad:
a.actionPerformed(null);

Wane jest, aby struktura klasy anonimowej bya znana kompilatorowi. Oznacza to,
e oprcz interfejsu klasa anonimowa moe redefiniowa istniejc klas. Nie ma
natomiast wikszego sensu wprowadzanie nowych metod do klasy anonimowej, gdy
pniej nie da si ich wykorzysta. Przykad klasy definiujcej metod make, ktrej
nie da si nastpnie uy, pokazany jest na listingu 2.77.
Listing 2.77. Niecelowe nazywanie egzemplarza klasy anonimowej
Object a = new Object() {
public void make() {
// ciao metody make
}
};
// bd: make nie istnieje w klasie Object
a.make();

88

Java. Programowanie obiektowe

Moemy prbowa rnych sztuczek w celu uycia metody make, na przykad zastosowa refleksje bd uywa nazwy klas tworzonej przez kompilator typu Applet$1
jako okrelajcej typ klasy, jednak rozwizania te s bardzo czasochonne i skomplikowane w kodzie, tak e nie opaca si uywa.

2.5.3. Konstruktor klasy anonimowej


Wikszo osb jest przekonana, e klasa anonimowa nie moe posiada konstruktora.
Tezy takie wynikaj najczciej z porwnania klasy anonimowej ze zwyk. W zwykej
(nazwanej) klasie konstruktor jest to metoda, ktra posiada nazw zgodn z nazw
klasy. Oczywiste jest, e skoro klasa nie ma nazwy, to nie bdzie moga mie metody
o tej samej nazwie. Naley jednak pamita, e poza konstruktorem istniej takie narzdzia jak inicjator klasy i inicjator egzemplarza klasy, czyli obiektu. Z powodzeniem moemy zastosowa go jako namiastk konstruktora. Biorc pod uwag, e klasa
anonimowa jest najczciej bardzo zuboona, trudno spodziewa si w jej przypadku
nadmiernie rozbudowanych konstruktorw. W zwizku z tym niemal zawsze w zastpstwie konstruktora moe wystpowa inicjator egzemplarza, tak jak na listingu 2.78.
Listing 2.78. Namiastka konstruktora w klasie anonimowej
interface Anonim {
void make();
}
Anonim a = new Anonim() {
// pola klasy implementujcej Anonim
{
// inicjator obiektu (w tym pl klasy anonimowej)
}
public void make() {
// ciao klasy Make
}
};

W przypadku koniecznoci przekazania parametrw do inicjatora klasy anonimowej


moemy skorzysta z lokalnych zmiennych finalnych, jak na listingu 2.79.
Listing 2.79. Przekazanie parametrw do inicjatora klasy anonimowej
final int i = 111;
Anonim a = new Anonim() {
int j;
{
j = i;
}
public void make() {
System.err.println("i ma warto: " + i);
}
};

Rozdzia 2. Klasy i obiekty w Javie

89

Jak to pokazaem w metodzie make, do niej rwnie moemy przekaza dane z zewntrz klasy anonimowej z uyciem zmiennej finalnej spoza klasy. Taka moliwo
dodatkowo ogranicza liczb przypadkw, kiedy uywanie inicjatora obiektu jest konieczne.

2.6. Obiekty refleksyjne


W podrozdziale 2.2. Obiekty pokazaem sposoby uywania obiektw o typie znanym i zdefiniowanym w czasie tworzenia kodu programu. Znajomo typu oznacza
w tym wypadku to, e kompilator jest w stanie odwoa si w czasie kompilacji do
pliku typu class zawierajcego definicj klasy, ktra posuy do utworzenia jej egzemplarza. Nie zawsze sytuacja taka jest moliwa. Moe si okaza, e waciwy plik
z definicj bdzie dostpny w pniejszym terminie (jest na przykad tworzony przez
drugi zesp programistyczny). Innym przykadem zastosowania moe by wykorzystanie gotowych klas w wizualnych rodowiskach programistycznych. rodowisko
takie powinno obsugiwa dowolne komponenty, nawet jeli powstay ju po utworzeniu caego korzystajcego z nich programu. Obiekty refleksyjne wykorzystuje si
rwnie jako sterowniki do komunikacji z urzdzeniami i programami zewntrznymi.
Dziki tej metodzie tworzenia obiektw skompilowany program moe si porozumie
z innym skompilowanym programem interaktywnie bez koniecznoci tworzenia
w tym celu dedykowanego kodu. Innym wanym zastosowaniem refleksji jest moliwo uruchomienia odrbnego programu napisanego w Javie znanego wycznie z nazwy.
Refleksji naley uywa wszdzie tam, gdzie zamierzamy tworzy egzemplarze klas,
ktre znamy wycznie z nazwy.
Dziki wprowadzeniu mechanizmu refleksji Java, jako jeden z niewielu jzykw programowania, umoliwia tworzenie i uywanie obiektw na przykad na podstawie
nazw klas wpisanych rcznie z uyciem klawiatury w trakcie dziaania programu.
Naley jednak pamita, e obiekty refleksyjne nie s czystym wykorzystaniem moliwoci jzyka, lecz biblioteki Javy. Mimo tego zdecydowaem si umieci opis tego
problemu w tym miejscu ze wzgldu na pokrewn tematyk zagadnienia.

2.6.1. Obiekt tworzony refleksyjnie


Najprostszym sposobem wykorzystania refleksji jest skorzystanie z konstrukcji:
Class.forName("nieznana_klasa").newInstance();

Zaprezentowany wiersz programu tworzy obiekt typu okrelonego przez klas znajdujc si w pliku nieznana_klasa.class. W celu utworzenia tego obiektu wykorzystuje bezparametrowy konstruktor tej klasy. W zwizku z tym, e nazwa pliku jest
zgodna z nazw klasy, ktra jest gwn klas tego pliku, utworzony obiekt jest typu
wanie nieznana_klasa. Twrcy klasy Class, ktra odpowiada za kreowanie obiektw w trybie refleksyjnym, musieli poradzi sobie z problemem obsugi klas dowolnych, niezaprojektowanych jeszcze typw. Metoda newInstance zwraca wic wskazanie

90

Java. Programowanie obiektowe

na nowo utworzony obiekt, jednak jest ono typu Object. Autorzy tej klasy skorzystali
tu z bezpiecznej konwersji typu zwanej te rozszerzeniem zakresu zmiennej. To znaczy otworzony obiekt typu nieznana_klasa zostaje przekazywany jako obiekt typu
Object. W praktyce wic powinno si uywa wczeniejszej konstrukcji w postaci:
Object o;
o = Class.forName("nieznana_klasa").newInstance();

Jakkolwiek konstrukcja ta wydaje si bardziej przydatna, w praktyce wymaga bardziej zaawansowanych dziaa opisanych dalej. Samo wskazanie na obiekt typu Object
jest bowiem w tej prostej postaci niemal nieprzydatne. Nieprzydatne, gdy klasa Object
nie posiada wasnoci, ktre tak naprawd nas interesuj. Aby mona byo uy tego
wskazania, powinno si dokona tak zwanej niebezpiecznej konwersji typu, czyli zawenia zakresu zmiennej:
Nieznana_klasa nk;
nk = (Nieznana_klasa)o;

Rozwizanie takie jest jednak niemoliwe, poniewa w chwili tworzenia programu


typ nieznana_klasa nie jest dla nas (i dla kompilatora) dostpny. Nie moemy utworzy typu, ktrego nie znamy. Czsto wic tworzy si obiekty refleksyjne wycznie
w celu skorzystania z kodu, ktry umieszczony jest w bezparametrowym konstruktorze. Jeli uywamy obiektw refleksyjnych jako sterownikw, mona temu zaradzi,
stosujc wytyczne dla twrcw klas, ktre bd uywane w ten sposb. Tak na przykad dzieje si w przypadku sterownikw JDBC (Java DataBase Connectivity). W specyfikacji opisujcej ten standard wymagane jest, aby tworzcy si obiekt sterownika
utworzy wskazanie do obiektu DriverManager, ktry bdzie w przyszoci wykorzystywany do obsugi bazy danych. Przykad praktycznego wykorzystania obiektu refleksyjnego w obsudze baz danych pokazany jest na listingu 2.80.
Listing 2.80. Uycie obiektu refleksyjnego w obsudze baz danych
import
import
import
import

java.awt.*;
java.awt.event.*;
java.applet.*;
java.sil.*;

public class silApplet


public ResultSet rst
public List silWynik
Button button1 = new

extends Applet {
= null;
= new java.awt.List(10);
Button();

public void init() {


String url = "jdbc:AvenirDriver://marekwi_nt5:1433/mwi";
Class.forName("net.avenir.jdbcdriver7.Driver"p.newInstance(p;
DriverManager.setLoginTimeout(30);
Connection ctn = DriverManager.getConnection(url, "konto", "haslo");
Statement stmt = ctn.createStatement();
boolean moreResult = stmt.execute("select * from tabela_SQL");
int updateCount = stmt.getUpdateCount();
rst = stmt.getResultSet();
silWynik.add("nagcwek bazy");
button1.setLabel("Nacinij, eby pobra kolejny rekord");
button1.addActionListener(new java.awt.event.ActionListener() {

Rozdzia 2. Klasy i obiekty w Javie

91

public void actionPerformed(ActionEvent e) {


button1_actionPerformed(e);
}
});
this.add(silWynik, null);
this.add(button1, null);
void button1_actionPerformed(ActionEvent e) {
String str;
try {
if(rst.next()) {
str = rst.getObject(1).toString() + "-" + rst.getObject(2).toString();
silWynik.add(str);
}
} catch(Exception ee) {
ee.printStackTrace();
}
}

Jak wida, w caym aplecie tylko jeden wiersz (wytuszczony) odpowiada za powstanie obiektu refleksyjnego. Pozostaa cz kodu bazuje na specyfikacji JDBC znanej
twrcom sterownika obsugi baz danych (no i oczywicie programistom). Takie rozwizanie jest nagminnie stosowane wanie w trakcie tworzenia sterownikw zewntrznych urzdze czy programw. Dziki niemu uytkownik dowolnej bazy danych
musi zna wycznie nazw sterownika skojarzon z posiadan baz, by po modyfikacji dwch wierszy programu mc uywa go w nowej wersji.

2.6.2. Oglne rozpoznawanie klasy


Poprzedni paragraf pokaza, jak wykorzysta ide refleksji do stworzenia wasnej
specyfikacji (na przykad sterownikw) i wykorzystania nieznanych obiektw do
z gry zaprojektowanej akcji. Nie zawsze jednak jestemy w tak komfortowej sytuacji, e tworzymy standard, ktry wypeniaj inni programici. Czasami bywa tak, e
musimy wykorzysta klas, ktrej zupenie nie znamy. Do penej analizy nieznanego
pliku moemy wykorzysta cztery specjalizowane w tym celu klasy: Class, Method,
Constructor i Field. Przykad najprostszego uycia tych klas pokazany jest na listingu 2.81.
Listing 2.81. Metody rozpoznawania obiektw refleksyjnych
import java.lang.reflect.*;
import java.applet.*;
public class aplet extends Applet {
public void init() {
int i;
try {
Class c = Class.forName("net.avenir.jdbcdriver7.Driver"p;
System.out.println("");
System.out.println("Lista metod z argumentami:");

92

Java. Programowanie obiektowe


Method m[] = c.getDeclaredMethods(p;
for (i=0; i<m.length; i++)
System.err.println(m[i].toString());
System.out.println("");
System.out.println("Lista konstruktorw z argumentami:");
Constructor ctrs[] = c.getDeclaredConstructors(p;
for (i=0; i<ctrs.length; i++)
System.err.println(ctrs[i].toString());

System.out.println("");
System.out.println("Lista pl:");
Field f[] = c.getDeclaredgields(p;
for (i=0; i<f.length; i++)
System.err.println(f[i].toString());
} catch (Throwable e) {
System.err.println(e);
}

Jak wida, wan rol w rozpoznawaniu struktury nieznanej klasy odgrywaj metody
getDeclaredXxxx (wytuszczone na wydruku) nalece do klasy Class, ktre zwracaj
jako wynik odpowiednio list metod, konstruktorw i pl wystpujcych w badanej
klasie. Klasa Class jest nadzorc klas refleksyjnych, ktra umoliwia do dokadne
zbadanie waciwoci analizowanej klasy. Poza najpopularniejszym sposobem tworzenia obiektu tego typu (wytuszczonego na ostatnim wydruku) mona go utworzy
dla typw podstawowych z uyciem konstrukcji:
Class c = int.class;

Ponadto dla klas usugowych, czyli obudowujcych typy podstawowe w klasy, mona
to zrobi, korzystajc z predefiniowanego pola TYPE:
Class c = Integer.TYPE;

Oba sposoby s raczej rzadziej spotykane ze wzgldu na to, e typy te s zawsze dostpne dla kompilatora i nie ma potrzeby uywania ich z uyciem refleksji.

2.6.3. Przykad uycia refleksji


Rozpoznanie struktury klasy to tylko poredni krok do faktycznego uycia obiektu
stworzonego refleksyjnie. Pene wykorzystanie obiektu wymaga uywania jego pl
i metod. Do wykorzystania w dalszym przykadzie stworzyem klas, ktra (listing
2.82) zawiera tylko dwa pola typu double.
Listing 2.82. Definicja klasy testowej
public class Test {
public double d1 = 0.1;
public double d2 = 0.2;
}

Rozdzia 2. Klasy i obiekty w Javie

93

Najprostszy przykad odczytu, a nastpnie ustawienia tych pl w klasie Test bdzie mia
posta zaprezentowan na listingu 2.83.
Listing 2.83. Refleksyjne operacje na polach klasy testowej
// egzemplarz klasy nadzorujcej
Class c = Class.forName("Test");
// egzemplarz obiektu refleksyjnego
Object o = Class.forName("Test").newInstance();
// nadzorcy poszczeglnych pl
Field fd1 = c.getField("d1");
Field fd2 = c.getField("d2");
// odczyt pl obiektu klasy test
System.out.println("d1 = " + fd1.getDouble(o));
System.out.println("d2 = " + fd2.getDouble(o));
// ustawienie pl
fd1.setDouble(o, 1.1);
fd2.setDouble(o, 2.2);
// sprawdzenie, czy operacja powioda si
System.out.println("d1 = " + fd1.getDouble(o));
System.out.println("d2 = " + fd2.getDouble(o));

W komentarzach zaznaczyem znaczenie poszczeglnych fragmentw programu. Tworzc przykad, zaoyem, e wiem, jakie bd nazwy i typy poszczeglnych pl.
Oczywicie w praktyce trzeba sprawdza zarwno ich typy, jak i nazwy (co pokazaem wczeniej) oraz przewidzie bardziej zaawansowane techniki wychwytywania
bdw. Warto zwrci uwag na do dziwn konstrukcj stosowan w powyszym
przykadzie:
fd1.getDouble(o);

Umoliwia ona odczyt pola obiektu o poprzez obiekt nadzorc refleksji pola. Konstrukcja ta jest o tyle dziwna, e w przypadku wikszej liczby pl argumentem jest
zawsze ten sam obiekt egzemplarz refleksyjny. Rozrnienie poszczeglnych pl
odbywa si poprzez rozrnienie nadzorcy ich refleksji. Jest to konwencja odwrotna
do naturalnego wykorzystania pl w obiekcie, gdzie zawsze uywamy tego samego
obiektu, natomiast zmieniaj si referencje do pl w nim.
Znacznie ciekawszym problemem jest wywoywanie metod z obiektw tworzonych
refleksyjnie. W dalszej czci tego paragrafu poka, jak wywoa metod add klasy
z listingu 2.84.
Listing 2.84. Definicja klasy testowej z metod
public class Testm {
public int add(int a, int b) {
return (a + b);
}
}

94

Java. Programowanie obiektowe

Na listingu 2.85 wykorzystam wiedz o strukturze tej klasy (jednak bez dostpu do
definicji jej typu) do uruchomienia jej jedynej metody z uyciem obiektw refleksyjnych.
Listing 2.85. Refleksyjne uycie klasy testowej z metod
// egzemplarz klasy nadzorujcej
Class cls = Class.forName("Testm");
// egzemplarz obiektu refleksyjnego
Object obj = Class.forName("Testm").newInstance();
// nadzorcy parametrw
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
// nadzorca metody
Method meth = cls.getMethod("add", partypes);
// egzemplarze parametrw
Object arglist[] = new Object[2];
arglist[0] = new Integer(11);
arglist[1] = new Integer(22);
// wywoanie metody
Object retobj = meth.invoke(obj, arglist);
// odbir wyniku
Integer retval = (Integer)retobj;
System.err.println(retval.intValue());

Jak wida, technika jest podobna do stosowanej w przypadku obsugi pl, chocia
oczywicie jest nieco bardziej skomplikowana ze wzgldu na konieczno dodatkowej obsugi parametrw wywoywanych funkcji. Zaprezentowany przykad korzysta
z wiedzy na temat struktury uywanej metody (parametrw i wyniku). W praktyce
powyszy przykad powinien by rozszerzony o badanie tych elementw i obsug
ewentualnych bdw. Mona na przykad stworzy z uyciem tej metody zaawansowany kalkulator, w ktrym uytkownik kocowy mgby dodawa swoje funkcje
automatycznie rozpoznawane na podstawie nazwy.

2.6.4. Zwizek refleksji z obiektowoci


Moliwoci refleksji nie rozszerzaj w aden istotny sposb idei programowania
obiektowego. Z punktu widzenia tej idei jedyn, acz wtpliw zalet jest moliwo
dogbnego sprawdzenia struktury klasy, ktrej nie jestemy autorami. Jednak jeli
klasa zostaa dobrze zaprojektowana, to analiza taka nie powinna nam przynie adnych dodatkowych korzyci. Wszak hermetyzacj i ukrywanie niektrych cech implementacyjnych wprowadzono po to, by nie zaciemnia programu niepotrzebnymi
szczegami, ktrych znajomo nie wnosi adnej nowej wiedzy do procesu dziaania
tego obiektu.
Stosujc refleksje, naley pamita o rnicy midzy egzemplarzem klasy nadzorujcej refleksje, a samym egzemplarzem obiektu refleksyjnego. Jeli nie nastpi pomieszanie obu poj, to nie powinno by problemw z waciwym stosowaniem tej ciekawej cechy Javy udostpnianej przez jej bibliotek.

Rozdzia 2. Klasy i obiekty w Javie

95

2.7. Metody
Metody to poczone w jedn cao zbiory instrukcji, ktre umoliwiaj wykonywanie akcji charakterystycznych dla danego obiektu bd zmieniaj jego stan. Przy opisywaniu sposobw tworzenia klas wprowadziem informacje dotyczce uywania
metod jako caoci, nie wgbiajc si w szczegowe zasady dziaania rzdzce ich
tworzeniem. Teraz zajm si kwestiami zwizanymi z wewntrzn struktur metod
i sposobem porozumiewania si kodu wewntrznego metody z kodem, ktry j wywouje. Wikszo pokazanych tu kwestii dotyczy rwnie konstruktorw, ktre niemal nie rni si w swojej budowie od metod.
Metody to kolejny element ukadanki skadajcej si na obiektowy sposb programowania. Pozwalaj ukrywa bardziej rozbudowane operacje pod nazw metody.
Bardzo podobne znaczenie maj funkcje i procedury w zwykym programowaniu
strukturalnym. Jednak cech metod jest to, e mog dziaa na danych nalecych do
obiektu, czyli do konkretnego egzemplarza klasy. Jeli w zwykym programowaniu
strukturalnym funkcja odwouje si do pewnej zmiennej zadeklarowanej poza jej ciaem, to zawsze odwouje si do tej samej zmiennej (do jednego jej egzemplarza).
W programowaniu obiektowym jest inaczej. Tworzc egzemplarze klas, tworzymy
zestawy danych zwizanych z pewn metod. Moemy tworzy wicej takich samych
egzemplarzy i wywoanie metod wiza z konkretnymi zestawami danych, czyli obiektami. Dziki temu metoda moe dziaa za kadym razem na danych zewntrznych,
ale przechowywanych specjalnie na potrzeby tej i innych metod tego obiektu. Kolejnym z celw stosowania metod jest, poza ukrywaniem wikszej grupy dziaa pod
jedn nazw, zwikszenie hermetyzacji obiektw. Klasyczna sugestia programowania
obiektowego (o ktrej ju kilkukrotnie wspominaem w tym rozdziale) mwi, e we
wszystkich moliwych sytuacjach w klasach naley stosowa pola o statusie prywatnym,
to znaczy niedostpnym i niewidzialnym spoza obiektu. Dostp do tych metod zapewnia si wanie przez odpowiednie metody ustawiajce i zwracajce warto pola.

2.7.1. Zwracanie wartoci przez metod


Metody s uruchamiane jako dziaania na danym obiekcie. Wykorzystuje si w tym
celu referencj obiektu i nazw tej metody z list jej parametrw:
obiekt.metoda(lista parametrw);

bd
zmienna = obiekt.metoda(lista parametrw);

To, czy metoda zwraca jak warto czy nie i jakiego typu jest ta warto, deklarujemy w czasie jej definiowania. Metoda, ktra nie zwraca adnej wartoci, musi by
deklarowana jako posiadajca typ void:
void metoda() {
// ciao metody
}

96

Java. Programowanie obiektowe

Poza deklaracj typu w ciele metody nie musz by wykonywane adne czynnoci
zwizane ze zwrotem parametrw (nie trzeba dodawa adnych instrukcji). Nieco inaczej jest w metodach zwracajcych warto. Na listingu 2.86 jest to warto typu int.
Listing 2.86. Sposb zwracania wartoci przez metod
int metoda() {
int cur;
// ciao metody ustawiajce warto cur
return cur;
}

Poza deklaracj typu konieczne jest przekazanie do miejsca wywoania wartoci wyznaczonej w ciele metody z uyciem instrukcji return. Przypisanie wartoci w miejscu wywoania metody polega na skorzystaniu z kopii zmiennej wymienionej w instrukcji return.
Specjalnym wypadkiem jest konstruktor, ktry deklarujemy bez adnego typu, ale
rwnie bez sowa void. W rzeczywistoci konstruktor zwraca warto bdc wskazaniem na egzemplarz klasy, wewntrz ktrej jest zadeklarowany. Zwracaniem tego
parametru zajmuje si jednak JVM, wic nie musimy si o to martwi, a tym bardziej
nie musimy uywa w nim instrukcji return, ktra jest odpowiedzialna za tak operacj.

2.7.2. Przekazywanie parametrw przez warto


Wywoanie kadej metody wymaga dostarczenia okrelonej w jej definicji liczby parametrw, przy czym musz one by dokadnie tego samego typu, jak jest to okrelone.
Pod pojciem dokadnie tego samego typu ukrywa si te przypadek, gdy na parametrach moe zosta zastosowana konwersja typu (przypadek ten dotyczy przekazywania obiektw). Pewnym pozornym wyomem s metody przecione, gdzie wystpuje
pewna dowolno w liczbie i typach parametrw. Dowolno wystpuje jednak wycznie w zakresie przewidzianym w czasie projektowania metod o tej samej nazwie.
Standardowo parametry metod w Javie przekazywane s przez warto. Oznacza to,
e w czasie wywoania metody tworzone s kopie zmiennych, ktre przekazuje si do
wntrza metody pod postaci parametrw. Jeli wic wywoamy metod dodaj1 z parametrem typu int, to zmiana wartoci tego parametru wewntrz metody nie wpynie
na warto zmiennej uytej w wywoaniu. Do zaprezentowania problemu posuy
przykad z listingu 2.87.
Listing 2.87. Obiekt prezentujcy zasig zmiennych
import java.applet.*;
public class Applet2 extends Applet {
public void init() {
int i = 1;
System.err.println("warto przed:
dodaj1(ip;
System.err.println("warto po:
}

" + ip;
" + ip;

Rozdzia 2. Klasy i obiekty w Javie

97

void dodaj1(int jp b
j = j + 1;
System.err.println("warto wewntrz: " + jp;
}
}

Uruchomienie tego przykadu spowoduje wywietlenie na konsoli Javy trzech wierszy


tekstu pokazanych na rysunku 2.10.
Rysunek 2.10.
Wydruk generowany
przez program 2.87

warto przed:
1
warto wewntrz: 2
warto po:
1

Jak wida, zmiana wartoci kopii nie wpyna na warto oryginau przekazywan do
metody. Sytuacja nie zmieniaby si nawet wtedy, gdyby nazwa parametru i pola pokryway si.

2.7.3. Zmiana wartoci parametru


Formalnie rzecz ujmujc, parametry s przekazywane do metod przez warto. Nie
jest wic moliwa zmiana pewnej wartoci wewntrz metody tak, aby byo to widziane na zewntrz. Mona tego dokona, zwracajc ten sam parametr w postaci wartoci
funkcji. Mona te skorzysta z cechy Javy, o ktrej pisaem w podrozdziale 2.2.3.
Kopiowanie obiektw. Ot w momencie wywoania tworzona jest kopia zmiennej
przekazywanej do metody. Jeli jest to obiekt, to tworzona jest jego kopia (a nie jest
on klonowany). Obiektu tego nie moemy zmodyfikowa jako caoci, to znaczy nie
moemy podstawi w to miejsce innego, bd go zwolni tak, aby efekt by widoczny
poza metod. Jak jednak wczeniej pokazaem, modyfikowanie wartoci pl kopii
obiektu wpywa na zmian wartoci rwnie oryginau. Std ju bliska droga do mechanizmu znanego w innych jzykach, czyli zmiany wartoci parametru wewntrz
metody. W przykadzie z listingu 2.88 wykorzystam specjalnie w tym celu utworzon
klas Int, cho mona rwnie korzysta z klas dostpnych w bibliotekach Javy, w tym
z usugowych powielajcych typy proste.
Listing 2.88. Zmiana parametru wewntrz metody widziana na zewntrz
class Int b int i; }
Int i = new Int(p;
i.i = 1;
System.err.println("warto przed:
dodaj1(ip;
System.err.println("warto po:
// ...

" + i.i);
" + i.i);

void dodaj1(Int jp b
j.i = j.i + 1;
System.err.println("warto wewntrz: " + j.ip;
}

98

Java. Programowanie obiektowe

Wynik dziaania tego programu to wywietlone na konsoli Javy napisy (rysunek 2.11):
Rysunek 2.11.
Wydruk generowany
przez program 2.88

warto przed:
1
warto wewntrz: 2
warto po:
2

Wane jednak jest, e do wntrza metody dodaj1 naley przekaza wskazanie do


obiektu, a nie samo pole. Na listingu 2.89 zastosowano bdne podejcie.
Listing 2.89. Bdne podejcie do modyfikacji wartoci przez metod
class Int { int i; }
Int i = new Int();
i.i = 1;
System.err.println("warto przed:
" + i.i);
dodaj1(i.i); // bdne przekazanie wartoci pola
System.err.println("warto po:
" + i.i);
// ...
void dodaj1(int j) { // konieczno modyfikacji
j = j + 1;
System.err.println("warto wewntrz: " + j);
}

Efekt dziaania takiego bdnego podejcia byby taki, jak w klasycznym przekazywaniu parametru przez warto (rysunek 2.12).
Rysunek 2.12.
Wydruk generowany
przez program
z listingu 2.89

warto przed:
1
warto wewntrz: 2
warto po:
1

Naley pamita o tym, e to nie przynaleno do obiektu powoduje inne traktowanie parametru, lecz przekazywanie adresu do kopii obiektu, a nastpnie dziaanie na
jej polach, co jest rwnoznaczne z dziaaniami na samym obiekcie. Gdybymy chcieli
przekazywa do metody obiekt w taki sposb, aby efekt dziaania na nim nie by widoczny na zewntrz metody, naleaoby przekazywa do niej jego klon.
Identyczne dziaanie jak przekazywanie referencji do obiektu mona osign, przekazujc referencj do tablicy (nawet jednoelementowej). Dziki takiej sztuczce mona zmusi Jav do modyfikacji wartoci parametru bez przekazywania go jako obiekt,
co pokazaem na listingu 2.90.
Listing 2.90. Modyfikacja wartoci parametru niebdcego obiektem
int[] a = new int[1];
a[0] = 15;
razy2(a);
// a[0] ma teraz warto 30
void razy2(int[] a) {
a[0] = 2 * a[0];
}

Rozdzia 2. Klasy i obiekty w Javie

99

Jak wida, jest to prostsze rozwizanie ni zastosowanie obiektw i doskonale sprawdza


si zwaszcza w prostych dziaaniach. Trzeba jednak pamita, e stosujc to rozwizanie, naley bardzo uwaa, gdy nie kontrolujemy w nim parametrw (w metodzie
razy2 nie sprawdziem, jaka wielka jest przekazywana do niej tablica).

2.7.4. Metody ze zmienn liczb parametrw


Przecianie metod jest sposobem na konstruowanie obiektw z wiksz liczb metod
o tej samej nazwie, lecz rnym zestawie parametrw. Kwestia ta bya ju omwiona
w paragrafie 2.1.5. Przecianie metod. Z punktu widzenia konstrukcji metod ich
przecianie nie jest jednak adnym szczeglnym przypadkiem. Polega po prostu na
budowaniu kilku metod o rnym zestawie parametrw. Ciekawszym rozwizaniem
s metody o zmiennej liczbie parametrw, cho formalnie, o czym wczeniej ju pisaem, Java nie umoliwia ich stosowania. Moemy jednak zastosowa rozwizanie,
ktre umoliwi przesanie ich w takiej liczbie, jaka jest akurat wymagana w momencie wywoania takiej nietypowej metody. Klasyczny sposb przekazywania parametrw bazuje na ich staej, okrelonej w czasie definiowania metody liczbie. Niewielkim
nakadem pracy mona jednak skorzysta z mechanizmu dynamicznego przekazywania parametrw, ktry umoliwi oderwanie si od stosowania staej ich liczby. Metody takie s nagminnie wykorzystywane w innych jzykach bez szkody, a czsto nawet
z korzyci dla przejrzystoci, atwoci i szybkoci tworzenia kodu. W Javie mechanizm taki, jakkolwiek dostpny, nie jest zbytnio eksponowany. W zwizku z tym, e
uwaam metody ze zmienn liczb parametrw za mniej niebezpieczne od mechanizmu ich przeciania, przedstawi na listingu 2.91 sposb realizacji tego przypadku.
Listing 2.91. Przekazywanie do metody zmiennej liczby parametrw
void zmienneParametry(Object params[]) {
for (int i=0; i<params.length; i++) {
System.err.println(params[i].getClass());
System.err.println(params[i]);
}
}

Formalnie zaprezentowana metoda odbiera tablic obiektw. Jeli jednak uwzgldni


si fakt, e standardowa biblioteka klas Javy, obowizkowo znajdujca si w kadym
rodowisku tego jzyka, zawiera zestaw klas usugowych odpowiadajcych typom prostym, mona przyj, e do metody moemy przekaza kady rodzaj parametrw:
ZmienneParametry(new Object[]
{"tekst", new Boolean(true), new Integer(5)});

Wynik dziaania tak wywoanej funkcji zaprezentowany jest na rysunku 2.13.


Rysunek 2.13.
Efekt przekazania
rnych parametrw
do metody

class java.lang.String
tekst
class java.lang.Boolean
true
class java.lang.Integer
5

100

Java. Programowanie obiektowe

Jak wida, wewntrz metody mona okreli typ przekazanych do niej parametrw,
co wydatnie podnosi funkcjonalno tego rozwizania. Do penego okrelenia typu
obiektu przesyanego do metody powinno uy si operatora instanceof, o ktrym
pisaem w podrozdziale 2.2.5. Typ zmiennej i obiektu. Operator instanceof.

2.7.5. Zakres nazw zmiennych


Opisujc sposb tworzenia metod, chciabym wspomnie te o zakresie widzialnoci
w ich obrbie nazw zmiennych i pl. Zmienna zadeklarowana w obrbie metody bd
parametr o nazwie takiej jak jej pole s wewntrz niej waniejsze ni nazwa pola
klasy. Na listingu 2.92 znajduje si podwojona deklaracja o nazwie use.
Listing 2.92. Przesanianie zmiennych o tej samej nazwie
class Test {
int use;
void testM() {
int use;
// operacje na use
}
}

Powoduje ona, e operacje na zmiennej use wewntrz metody testM nie bd miay
wpywu na stan pola use obiektu. Gdybymy chcieli mie dostp jednoczenie do
zmiennej i do pola, musielibymy uy (tak jak ja w wytuszczonym wierszu na listingu
2.93) znanej ju referencji this do biecego obiektu.
Listing 2.93. Jednoczesny dostp do zmiennej i pola o tej samej nazwie
class Test {
int use;
void testM() {
int use = 0;
// podstawienie zmiennej lokalnej do pola:
this.use = use;
}
}

Takie podejcie ma zapewni bezpieczestwo w czasie rozszerzania i dziedziczenia


klas. Moe si bowiem okaza, e w czasie rozszerzenia w jednej z nowych metod
wymagane jest zastosowanie nazwy zmiennej zgodnej z nazw pola. Aby nie zmodyfikowa przez przypadek wartoci pola, Java przykrywa t nazw z uyciem lokalnej
zmiennej, na ktrej wykonywane s wszystkie lokalne operacje.

Rozdzia 2. Klasy i obiekty w Javie

101

2.8. Pakiety
Zaprezentowane dotychczas przykady klas w Javie byy bardzo skromne. W zwizku
z tym nie pojawiy si jak na razie adne problemy wynikajce z konfliktw nazw
midzy rnymi klasami. W rzeczywistych duych projektach niepowtarzalno nazw
jest trudna do zrealizowania. Czsto moe si okaza, e potrzebujemy stworzy dwie
klasy lub wicej, dla ktrych najbardziej adekwatna nazwa jest ju gdzie uyta.
Gdyby nie mechanizm zarzdzania nazwami poszczeglnych klas szybko okazaoby
si, e nie moemy ju stworzy adnej nowej o logicznej nazwie. Jeli uwzgldni
moliwo importu klas napisanych przez jednego z wielu twrcw udostpniajcych
zasoby w internecie, wkrtce mogoby rwnie zabrakn nazw zoonych z zupenie
przypadkowych znakw. Aby zaradzi temu problemowi, wprowadzony zosta mechanizm pakietw. Umoliwia on stosowanie takich samych nazw klas z zastrzeeniem, e nale do rnych pakietw. W praktyce oznacza to na przykad, e moemy
utworzy trzy klasy o nazwie Grid tworzce i obsugujce siatki elementw rnego
rodzaju. Jedn dla danych tekstowych, jedn dla obrazkw i jedn dla przyciskw
(siatka przyciskw ekranowych to na przykad kalkulator). Pierwsza z klas naleaaby
do pakietu texts, druga pictures, a trzecia buttons. Dziki temu nie tylko moemy
zastosowa takie same nazwy, ale nazwa pakietu lepiej identyfikuje nasz klas.

2.8.1. Tworzenie pakietw


Kady plik z klas Javy poza ni sam moe zawiera cznie cztery rne sekcje
tworzce kompletny i w peni funkcjonalny plik. Sekcje te nie s w aden sposb wyrnione. Podzia ten jest tworzony wycznie na podstawie zawartoci pliku pogrupowanej wedug schematu z listingu 2.94.
Listing 2.94. Struktura pliku definiujcego klas
[deklaracja przynalenoci do pakietu]
[deklaracje uycia innych pakietw]
deklaracja klasy publicznej
[deklaracje klas prywatnych]

Elementy ujte w nawiasy kwadratowe s opcjonalne. Tak wic klasa nie musi nalee do adnego pakietu i nie musi adnego z nich importowa, a przynajmniej tak si
wydaje. Jednak powiedzenie, e klasa nie naley do adnego pakietu, nie jest prawdziwe, bo wszystkie do jakiego nale. Jeli nie jest on jawnie nazwany, wtedy klasa
naley do nienazwanego pakietu domylnego. Oglna posta deklaracji przynalenoci klasy do pakietu wyglda tak:
package pakiet1[.pakiet2[.pakiet3]];

Wytuszczony fragment linii to sowo kluczowe informujce kompilator, e nastpujca


po tym sowie sekwencja jest nazw pakietu. Pakiety mog by grupowane w struktury hierarchiczne z uyciem kolejnych pakietw wedug podobnej zasady, jak nale
do nich klasy. Tak wic w skrajnym przypadku kilka klas naley do pakietu rzdu
pierwszego. Kilka pakietw rzdu pierwszego naley do drugiego. Struktur mona

102

Java. Programowanie obiektowe

zagbia dalej. Kolejne poziomy hierarchii oddzielone s w kodzie rdowym kropkami.


Struktura nazw pakietw musi odpowiada strukturze i pooeniu plikw w podkatalogach. Tak wic jeli gwny plik aplikacji znajduje si w katalogu c:\java\src,
wtedy pliki z klasami nalecymi do pakietu grafika musz lee w katalogu c:\java\
src\grafika, a pliki z pakietu grafika.obrazki musz znajdowa si w katalogu
c:\java\src\grafika\obrazki. W praktyce moe okaza si, e pliki z klasami nalecymi do tych pakietw le w rzeczywistoci w innych katalogach. Katalog rdowy ustalany jest bowiem na podstawie zmiennej rodowiskowej bd parametru
CLASSPATH. Jeli wic zmienna ta wskazuje na dwa rne katalogi, na przykad
c:\java\ibm\src i c:\java\sun\src, wtedy klasy pakietu grafika mog znajdowa si
zarwno w katalogu c:\java\ibm\src\grafika, jak i w c:\java\sun\src\grafika. Jeli nie wymienimy jawnie nazwy pakietu, do ktrego naley dana klasa, oznacza to, e
klasy bd szukane wycznie w katalogach wskazywanych przez CLASSPATH, a w niektrych wersjach Javy i jej kompilatorw take w katalogu biecym. W praktyce
bardzo czsto stosuje si kompresj wszystkich tworzonych przez nas klas do jednego
archiwum (typu jar bd zip) z uyciem hierarchicznej struktury katalogw. Zmienne
CLASSPATH bd odpowiedni parametr uruchomienia apletu wskazuj wtedy na konkretny plik jar, wewntrz ktrego znajduj si waciwe klasy we waciwych podkatalogach. Aby pokaza zagniedenie pakietw oraz moliwo stosowania w nich
takich samych nazw bez wprowadzania konfliktw, prezentuj na listingu 2.95 zestaw
pakietw dostpnych w Javie 1.1.
Listing 2.95. Lista pakietw dostpnych w Javie 1.1
java.applet
java.awt
java.awt.datatransfer
java.awt.event
java.awt.image
java.beans
java.io
java.lang
java.lang.reflect
java.math
java.net
java.rmi
java.rmi.dgc
java.rmi.registry
java.rmi.server
java.security
java.security.acl
java.security.interfaces
java.sil
java.text
java.util
java.util.zip

Warto zauway, e czsto zdarza si, e na tym samym poziomie zagniedenia wystpuj zarwno klasy, jak i kolejne pakiety. Dla przykadu mog wystpi pliki nalece do pakietu java.util oraz pakiet do niego nalecy. Daje to moliwo lepszego
wydzielania i gromadzenia klas w sposb bardziej oczywisty i zgodny z modelem
hermetyzacji obiektowej.

Rozdzia 2. Klasy i obiekty w Javie

103

2.8.2. Uywanie pakietw


Po wprowadzeniu informacji, w jaki sposb tworzy klasy, aby nie wystpoway midzy nimi konflikty nazw i znajdoway si w rnych pakietach, poka, w jaki sposb
uy tych pakietw. Jak to wczeniej pokazaem, plik zawierajcy klas Javy posiada
sekcj deklarujc uywanie pakietw. Sekcja ta skada si z dowolnej liczby linii
o postaci:
import pakiet[.pakiet[.pakiet]].klasa;

Kada z takich linii informuje kompilator oraz maszyn Javy o miejscu, gdzie naley
szuka elementw uywanych przez projektowan klas. Ostatnim sowem w hierarchii pakietw doczanej do biecego pliku jest klasa, ktrej zamierzamy uywa.
Moe to by konkretna klasa, ktrej nazw znamy, bd * (gwiazdka) oznaczajca, e
importujemy wszystkie elementy z tego pakietu (to znaczy wszystkie klasy i wszystkie interfejsy). Najczciej stosuje si gwiazdk, jednak dla bardzo duych projektw
nie jest to rozwizanie optymalne. Zastosowanie importu wszystkich klas z pakietu
powoduje, e kompilator w czasie tworzenia programu przeglda wszystkie pakiety,
z ktrych umoliwiamy uycie wszystkich klas. Najczciej trwa to do dugo, dlatego
warto maksymalnie ograniczy zakres importowanych klas. Nadmierny import nie ma
jednak wpywu na wielko wynikow klasy i szybko dziaania programu. Klasy
nalece do tego samego pakietu co bieca nie musz by importowane.
Hierarchia pakietw jest odnoszona w stosunku do ustawienia zmiennej CLASSPATH
oraz rzeczywistej struktury katalogw. Oznacza to, e pakiet:
grafika.przyciski

przy ustawieniu:
CLASSPATH=c:\java\src\

powinien znajdowa si w katalogu:


c:\java\src\grafika\przyciski\

Jakkolwiek wszystkie klasy pakietu, do ktrego naley bieca klasa, s widziane


z poziomu jej pliku, to widzialno ta nie przenosi si na podpakiety. To znaczy jeli
(przy zaprezentowanym wczeniej ustawieniu zmiennej CLASSPATH) mamy klas:
package aa.bb;
class B { }

znajdujc si w katalogu c:\java\src\aa\bb, wtedy klasa A dziedziczca po B, znajdujca si w pakiecie bb i umieszczona w katalogu C:\java\src\aa musi mie posta:
package aa;
import aa.bb.*;
class A extends B { }

W deklaracji import musimy wymieni peny dostp do pakietu aa.bb, gdzie znajduje
si klasa B, po ktrej dziedziczy A, mimo tego i formalnie znajduje si ona tylko o jeden szczebel niej. Wydawaoby si wic, e mona dokona importu z uyciem deklaracji:
import bb.*;

104

Java. Programowanie obiektowe

Byoby to moliwe, gdyby zmienna CLASSPATH zawieraa poza wskazaniem na konkretne katalogi wskazanie na katalog biecy. Mona tego dokona, dodajc do tej
zmiennej kropk, ktra reprezentuje wanie katalog biecy. Warto wiedzie, e niektre kompilatory Javy domylnie dziaaj tak, jakby uytkownik korzysta z takiego
ustawienia. Powinno si o tym pamita przy zmianie kompilatora, moe si bowiem
okaza, e projekt, ktry dotychczas kompilowa si zupenie poprawnie, przestaje si
kompilowa ze wzgldu na zmian traktowania biecego katalogu.
Warto te zauway, e import nie dotyczy podkatalogw i podpakietw. Gdybymy
wic chcieli w programie uy zarwno klasy A, jak i jej nadrzdnej B, musimy zaimportowa oba pakiety:
import aa.*; // aa.bb.* nie jest importowane
import aa.bb.*;

Stosowanie deklaracji import nie jest jednak jedynym sposobem na skorzystanie


z klas zdefiniowanych w odrbnych pakietach. Klas tych mona uywa, stosujc
pene nazwy z zachowaniem caej hierarchii pakietw. Pokazany wczeniej przykad
klasy A dziedziczcej wasnoci po B, ktra zdefiniowana zostaa w pakiecie aa.bb bez
deklaracji importu, bdzie mia posta:
package aa;
class A extends aa.bb.B { }

Jak wida, mona byo zrezygnowa z deklaracji importu na rzecz rozszerzenia nazwy klasy o nazw pakietu (na przykadzie wytuszczone).
Proste programy i aplety, ktre zawieraj stosunkowo niewielk liczb nowych projektowanych komponentw, mog by tworzone w ramach pakietw bez nazwy.
Wszystkie klasy nalece do projektu z domylnym pakietem bd wtedy pozbawione
linii z deklaracj package, ktra deklaruje przynaleno klasy do pakietu. Wszystkie
te klasy bd take widoczne w caym projekcje bez koniecznoci importowania ich.
W takim przypadku wszystkie klasy musz znajdowa si w jednym katalogu dyskowym. Czsto spotyka si konwencj, e klasy uytkowe stanowice bibliotek uytecznych komponentw umieszczane s w pakietach, ktre tworz biblioteki uytkownika, natomiast ostateczny projekt zawiera si w pakiecie bez nazwy. Takie
podejcie jest realizacj mylenia obiektowego na poziomie caych komponentw.
Projekt gwny jest widoczny dla programisty w sposb naturalny, natomiast wszystkie jego potrzebne elementy, ktrych szczegy implementacji nie s dla niego istotne,
s ukryte w pakietach. Korzystajc z modyfikatorw zakresu widzialnoci, moemy te
szczegy udostpnia bd dalej ukrywa zgodnie z wasn koncepcj hermetyzacji.

2.8.3. Lista pakietw


Jeli tworzymy aplikacje bd aplety z wykorzystaniem Javy 1.3 lub wyszej, moemy skorzysta z klasy Package, ktra umoliwi nam wywietlenie poytecznych informacji na temat wszystkich uywanych pakietw. Moe ona by na przykad uyta
do sprawdzenia, ktre klasy naley doczy do archiwum jar zawierajcego niestan-

Rozdzia 2. Klasy i obiekty w Javie

105

dardowe klasy (niedostpne w przegldarkach). Metoda wywietlajca list uywanych pakietw powinna by skonstruowana wedug schematu z listingu 2.96.
Listing 2.96. Metoda wywietlajca list uywanych pakietw
void listPackages() {
Package[] allPackages = Package.getPackages();
System.out.println("All loaded packages:");
for(int i=0; i < allPackages.length; i++) {
System.err.println(allPackages[i].getName());
System.err.println(" " + allPackages[i].getImplementationTitle());
System.err.println(" " + allPackages[i].getImplementationVersion());
}}

Informacje na temat pakietw pobierane s przez obiekt typu ClassLoader z archiwum


jar, z pliku manifest.mf. Przykadowy opis moe wyglda tak, jak to pokazuj na
rysunku 2.14.
Rysunek 2.14.
Przykadowa
zawarto
manifestu pliku jar

Name: java/mwi/grafika/3d
Specification-Title: Grafika 3D
Specification-Version: 1.0
Specification-Vendor: Sun
Implementation-Title: Najlepsza grafika 3D
Implementation-Version: 1.2.1
Implementation-Vendor: Helion

Tekst znajdujcy si przed dwukropkiem definiuje nazw parametru, a ten po dwukropku jego warto. W pakiecie moemy przekazywa cznie 7 parametrw,
przy czym zdarza si, e ClassLoader nie czyta ostatniej linii specyfikacji. Formalnie,
jeli brakuje danego wiersza, zwracana warto jest cigiem pustym. Przy cakowitym
braku opisu pakietu zwracane wartoci mog mie posta null.

2.9. Modyfikatory
Po wprowadzeniu wszystkich elementw obiektowych mog przystpi teraz do wyjanienia znaczenia poszczeglnych modyfikatorw, ktre wpywaj na rozszerzenie
funkcjonalnoci Javy bd te uczynienie jej jeszcze bardziej obiektowej. W dotychczasowych rozwaaniach, poza drobnymi wyjtkami, nie braem w aden sposb pod
uwag kwestii istnienia modyfikatorw. S to sowa kluczowe wystpujce przed deklaracjami klas, pl oraz metod ucilajce sposb dziaania lub zakres widzialnoci
elementu, ktrego dotycz. Modyfikatory te s opcjonalne. Jeli ich nie ma, kompilator przyjmuje domylne ustawienia jzyka dla poszczeglnych fragmentw kodu. Ich
stosowanie powoduje zmian wasnoci poszczeglnych elementw i dziki temu jest to
silne narzdzie wpywajce na realizacj wszystkich trzech elementw idei programowania obiektowego, czyli hermetyzacji, polimorfizmu i dziedziczenia. W zwizku
z brakiem modyfikatorw niektre z wczeniej wprowadzonych poj mogy si wydawa niepene bd niespeniajce rnorodnych oczekiwa uytkownikw. Dopiero

106

Java. Programowanie obiektowe

wprowadzenie modyfikatorw umoliwi rozwinicie penych moliwoci programowania obiektowego. Przedstawiajc modyfikatory, bd si stara zwraca Ci uwag
na miejsca, w ktrych wnios one nowe moliwoci i gdzie naley zweryfikowa
swoje pogldy na temat ju wprowadzonych konstrukcji. W Javie moemy rozrni
modyfikatory zmieniajce przestrze nazw oraz funkcjonalno elementu. Na przestrze nazw wpywaj modyfikatory private, public i protected. Na dziaanie i wasnoci wpywaj sowa static, final, volatile, synchronized, transient i native.
Modyfikatory mog wystpowa w dowolnej kolejnoci i czy si we w miar dowolne grupy, z zastrzeeniem, e modyfikator przestrzeni moe wystpi tylko raz, to
znaczy nie mona stworzy pola, ktre bdzie jednoczenie na przykad rodzaju public
i private.

2.9.1. Modyfikatory dostpu


Brak modyfikatorw jest rwnoznaczny ze stosowaniem dla klas, pl i metod domylnego sposobu ich traktowania. W praktyce oznacza to, e sterowanie dostpnoci
do poszczeglnych elementw odbywa si za pomoc waciwego rozmieszczania
tych elementw w klasach i pakietach. W Javie rozrniamy pi obszarw i zakresw
dostpnoci elementw. Tabela 2.1 okrela zakres widzialnoci elementu w zalenoci od zastosowanego modyfikatora.
Tabela 2.1 Zakres widzialnoci elementw w zalenoci od modyfikatora
Wntrze klasy,
w ktrej
zadeklarowany
jest dany
element

Modyfikator

Podklasy
znajdujce si
w tym samym
pakiecie

Inne klasy
znajdujce si
w tym samym
pakiecie

Podklasy
znajdujce
si w innych
pakietach

Inne klasy
znajdujce
si w innych
pakietach

private

Tak

Nie

Nie

Nie

Nie

(bez
modyfik
atora)

Tak

Tak

Tak

Nie

Nie

protected

Tak

Tak

Tak

Tak

Nie

public

Tak

Tak

Tak

Tak

Tak

Z niewiadomych powodw twrcy Javy zrezygnowali w nowszej specyfikacji jzyka


z moliwoci uywania ciekawego modyfikatora, ktry by kombinacj private i protected i by dostpny wycznie w Javie 1.0. Umoliwia on ustawienie widzialnoci
elementu wycznie w podklasach, bez wzgldu na to, czy naleay one do tego samego pakietu czy do innych. Nieznacznie rnio si to od standardu protected, ktry
poza widzialnoci w podklasach zapewnia widzialno w innych klasach tego samego
pakietu.
Analizujc modyfikator private w odniesieniu do klas lokalnych, naley zwrci uwag,
e nie dziaa on w peni tak, jakbymy oczekiwali. Listing 2.97 ukazuje klas lokaln
zadeklarowan z metod prywatn.

Rozdzia 2. Klasy i obiekty w Javie

107

Listing 2.97. Klasa lokalna z metod prywatn


public int i;
private class Lokalna {
private int wynik() { return i; }
}

Takie rozwizanie powoduje, e metoda wynik prywatna dla tej klasy jest jednak widoczna poza ni. Kompilator nie zgosi bdu przy kompilacji fragmentu programu z listingu 2.98.
Listing 2.98. Niekonsekwencja prywatnoci w klasie z listingu 2.97
void doSth() {
i = 100;
Lokalna l = new Lokalna();
System.err.println("wynik: " + l.wynik());
}

Metody i pola prywatne z zaoenia nie powinny by widoczne poza klas, tak wic
osobicie oczekiwaem, e metoda wynik nie bdzie widzialna dla kompilatora. We
wczesnych subwersjach Javy 1.1 pola i metody prywatne klas lokalnych byy traktowane inaczej, to znaczy pola prywatne byy niewidoczne, a metody prywatne widoczne.
Bd ten naprawiono i w wyszych wersjach zarwno pola, jak i metody prywatne s
widoczne poza klas. Moim zdaniem jest to niezgodne z konwencj modyfikatora
private. Korzystajc z niego w klasach lokalnych, naley wic pamita o tej niecisoci. Na modyfikator private zwracaem te uwag w paragrafach 2.1.4. Hermetyzacja i modyfikator private oraz 2.1.11. Kolejno inicjacji klas.

2.9.2. Pokrywanie modyfikatorw dostpu


Raz nadany zakres dostpu moe zosta w przyszoci rozszerzony. Oznacza to, e jeli zadeklarowalimy metod bez modyfikatora, metoda pokrywajca moe rwnie
tak by zadeklarowana oraz z modyfikatorami protected lub public. Jeli deklarujemy
metod jako protected, pokrywajc j, moemy (poza tym samym modyfikatorem)
uy modyfikatora public. Oczywicie moemy rwnie przedeklarowa zakres
private na dowolny inny. Jakkolwiek konwencja jest zachowana w stosunku do wymienionych wczeniej ukadw, wynika to z faktu, e element prywatny jest niewidoczny poza swoj klas. Odwrotna sytuacja nie jest moliwa, to znaczy zakres widzialnoci nie moe zosta zawony. Tak wic, jeli deklarujemy klas:
public class A {
int mi() {
return 0;
}
}

wtedy ponisza deklaracja jest poprawna:


public class B extends A {
public int mi() { return 0; }
}

108

Java. Programowanie obiektowe

natomiast nastpna ju nie:


public class B extends A {
private int mi() { return 0; } // bd kompilacji
}

Wyjtek dotyczy jedynie zakresu widzialnoci klas. Oznacza to, e jeli mamy w pewnym pakiecie deklaracj klasy:
package ppp;
public class P { }

wtedy moemy zawzi widzialno klasy potomnej w nastpujcy sposb:


package ppp;
class Q extends P { }
// zakres widzialnoci tylko w obrbie pakietu

Przy tak zadeklarowanych klasach prba uycia:


import ppp.*;
class Z {
P p = new P();
Q i = new Q(); // klasa niewidoczna
}

w przypadku klasy Q zakoczy si niepowodzeniem.


Wrmy jednak do widzialnoci metod. Zadeklarujmy klasy A i B w sposb podany na
listingu 2.99.
Listing 2.99. Przykadowa deklaracja dwch klas
package ppp;
public class A {
int mi() { return 0; }
}
package ppp;
public class B extends A {
public int mi() { return 0; }
}

Jak si naleao spodziewa, prba uycia metody mi obiektu a pokazana na listingu


2.100 nie powiedzie si, gdy metoda ta bdzie niedostpna.
Listing 2.100. Bdna prba uycia klas z listingu 2.99
import ppp.*;
class C {
A a = new A();
B b = new B();
void init() {
int i;
i = a.mi(); // metoda niedostpna

Rozdzia 2. Klasy i obiekty w Javie

109

i = b.mi();
}

Jednak bardzo dziwne jest to, e rwnie w przypadku prby pokazanej na listingu
2.101 dostp do tej metody bdzie niemoliwy.
Listing 2.101. Inna prba uycia klas z listingu 2.99
import ppp.*;
class C {
A a = new B(); // inny sposb tworzenia
B b = new B();
void init() {
int i;
i = a.mi(); // metoda niedostpna
i = b.mi();
}
}

Mam wraenie, e w tym przypadku, jakkolwiek referencja do metody mi dotyczy


klasy B, prawo dostpu do niej jest pobierane z typu zadeklarowanego, a nie rzeczywicie uywanego. Jest to wedug mnie pewna niespjno pomidzy rzeczywistym
typem rozpoznawanym przez JVM, a jego dostpnoci rozpoznawan przez kompilator, do ktrej naley si dostosowa.

2.9.3. Metody i pola statyczne


Poza modyfikatorami zakresu widzialnoci w Javie wystpuj modyfikatory okrelajce sposoby zachowania si bd umoliwiajce okrelenie nietypowych cech pl
lub metod. Jednym z takich modyfikatorw jest sowo kluczowe static. Moe ono
by stosowane cznie z modyfikatorami zakresu, to znaczy pole lub metoda statyczna moe by zarwno publiczna, prywatna, jak i domylna. Jakkolwiek istniej pewne
rnice w znaczeniu, ktre nadaje to sowo polom i metodom, jedno jest wsplne.
Ot zarwno pola, jak i metody statyczne mog by uyte bez koniecznoci tworzenia egzemplarza klasy. To znaczy zamiast tworzy obiekt, moemy odwoywa si do
tych pl i metod poprzez nazw klasy i nazw pola bd metody. Takie rozwizanie
upodabnia metody statyczne do funkcji globalnych w programowaniu strukturalnym,
a pola do zmiennych globalnych. Zalet jest jednak grupowanie tych zmiennych
i funkcji w grupy o wsplnej nazwie gwnej. Umoliwia to lepsze zarzdzanie tymi
elementami, a co za tym idzie czytelniejsz struktur programu, co jest jednym z gwnych celw obiektowego sposobu tworzenia aplikacji. Wemy deklaracj klasy przedstawion na listingu 2.102.
Listing 2.102. Metoda statyczna, ktra moe by uyta jak zwyka funkcja
class Globalne {
static int version = 12;
public static void libName() {

110

Java. Programowanie obiektowe


System.err.println("Funkcje globalne");
}

Klasy Globalne moemy uy w sposb pokazany na listingu 2.103.


Listing 2.103. Proste uycie metody statycznej
public void showLibName() {
Globalne.libName(p;
System.err.println("wersja: " + Globalne.version);
}

Wytuszczon czcionk zaznaczyem odwoanie bezporednio do klasy, bez tworzenia


jej egzemplarza.
Poza niestandardowym uyciem klasy pola statyczne s wsplne dla wszystkich egzemplarzy klas, czyli obiektw zawierajcych pola statyczne. Dziki tej wasnoci
umoliwiaj nam swoiste komunikowanie si midzy obiektami oraz zmian wartoci we
wszystkich egzemplarzach klasy za pomoc jednego przypisania. Jeli mamy przykadow klas o definicji:
class A {
static int a = 10;
}

wtedy przykad z listingu 2.104 dziaa w sposb niespotykany dla innych przypadkw.
Listing 2.104. Charakterystyczne zachowanie pola statycznego
public void init() {
// jeden egzemplarz klasy A:
A a = new A();
// drugi egzemplarz klasy A:
A b = new A();
// zmiana we wszystkich egzemplarzach klasy A:
a.a = 11;
System.err.println(a.a); // 11
// tu rwnie zmiana we wszystkich egzemplarzach:
b.A = 12;
System.err.println(a.a); // 12
}

Pierwsze przypisanie jest bardziej oczywiste i naturalne. Drugie moe powodowa


w niektrych sytuacjach trudne do wykrycia bdy (zmieniamy warto w jednej z klas,
a efekt pojawia si rwnie w innych). Jest to o tyle wane, e dokadnie taki sam
efekt osigniemy w przypadku zadeklarowania pola a klasy A jako prywatnego, jak to
zrobiem na listingu 2.105.
Listing 2.105. Zachowanie prywatnego pola statycznego
class A {
private static int a = 10;
public static void setA(int a) { A.a = a; }

Rozdzia 2. Klasy i obiekty w Javie

111

public static int getA() { return A.a; }


}
public void init() {
A a = new A();
A b = new A();
A.setA(11);
System.err.println(a.setA()); // 11
b.setA(12);
System.err.println(a.setA()); // 12
}

Dzieje si tak dlatego, e na pole statyczne w JVM miejsce jest rezerwowane tylko
jeden raz, w chwili definicji klasy. I wanie tam wpadaj wszystkie wartoci tego
pola bez wzgldu na to, w ktrym egzemplarzu klasy s uywane. Mona to traktowa jako pewnego rodzaju zmienn globaln dla wszystkich egzemplarzy klasy jednego typu.
W stosunku do pl statycznych naley rwnie pamita, e powinno si je inicjowa
w inicjatorze klasy, czyli bloku instrukcji opatrzonym deskryptorem static. Ponadto
konstrukcja metod statycznych powinna by zaprojektowana w taki sposb, aby wykorzystyway one wycznie inne metody statyczne oraz nie uyway wskaza this
i super. Warto te wiedzie, e deklarujc metod jako statyczn, blokujemy dziaanie
polimorfizmu. Jeli wic jaka klasa uywa metody statycznej, to bdzie uywaa zawsze
swojej wersji metody.

2.9.4. Pola finalne


Kolejnym modyfikatorem, ktry moe wystpowa ze sowami okrelajcymi zakres
widzialnoci i zmienia charakter pola, jest final. Umoliwia on tworzenie pl, ktrych warto nadawana jest tylko jeden raz i nie moe by ju pniej zmieniana. Taka
cecha jest podobna do zachowania si staych deklarowanych z uyciem sw const
w C++ czy Object Pascalu. Pola finalne musz by inicjowane w chwili ich tworzenia,
to znaczy wytuszczony fragment listingu 2.106 musi wystpowa w deklaracji pola.
Listing 2.106. Definicja pola finalnego
class A {
final int a = 10;
}

Pola finalne charakteryzuj si tym, e wszystkie s przechowywane w pamici w postaci jednego egzemplarza, dokadnie tak samo jak pola statyczne. Trudno to zauway w codziennym uyciu, gdy pola te musz by inicjowane, a jak pokazaem to we
wczeniejszej czci tego rozdziau, dzieje si to przed wywoaniem konstruktora.
Ponadto nie mog one zosta pokryte, jak dzieje si to w przypadku zwykych pl.
Mona to wykaza w stosunkowo karkoomnym przykadzie na listingu 2.107.

112

Java. Programowanie obiektowe

Listing 2.107. Bdna prba pokrycia pl finalnych


public void init() {
class A {
final int a = 10;
}
A[] a = new A[10];
int i;
for(i=0; i<10; i++) {
final int j=i;
a[i] = new A() {
final int a = j;
};
}
for (i=0; i<10; i++)
System.err.println(a[i].a);
}

Wbrew oczekiwaniom przykad ten spowoduje wywietlenie kolumny samych dziesitek. Warto pamita o takim zachowaniu w przypadku stosowania bardziej skomplikowanych konstrukcji jzykowych.

2.9.5. Metody i klasy finalne


W stosunku do metod i caych klas modyfikator final wprowadza cech podobn do
tej, ktra wystpia rwnie dla pl, to znaczy metody nie mog by pokrywane, a klasy
nie mog by rozszerzane przez dziedziczenie. Cecha ta umoliwia deklarowanie specyficznych klas, ktre na skutek krytycznej konstrukcji mogyby dziaa niepoprawnie w przypadku modyfikacji. Zabezpieczenie przed dalszym rozszerzaniem moemy
te stosowa w przypadku rozprowadzania wasnych obiektw jako bibliotek komponentw w celu wymuszenia pewnych specyficznych sposobw uycia.
Ponadto metody finalne mog si wykonywa szybciej w przypadku, gdy program
zosta skompilowany z opcj kompilatora -O. Opcja ta umoliwia rozwinicie metod
finalnych w miejscu ich wywoania podobnie jak dyrektywa inline w C++ czy Borland Pascalu. Taka rozwinita metoda oszczdza czas interpretera, gdy nie ma koniecznoci poszukiwania jej w czasie wykonania programu wrd kodu klas. Ponadto
zaoszczdza czas potrzebny na przekazanie parametrw do wntrza metody i na samo
jej wywoanie. W zwizku z tym warto stosowa t konstrukcj. Powinno si jednak
wiedzie, e takie dziaanie zwiksza kod wynikowy, co nie zawsze jest korzystne.
Poza tym nie ma gwarancji, e kod zostanie rozwinity, gdy moe si okaza, e
kompilator uzna tak akcj za nieopacaln i zrezygnuje z niej.

Rozdzia 2. Klasy i obiekty w Javie

113

2.9.6. Pola podlegajce zmianie


W rozdziale 6. Programowanie wielowtkowe zaprezentowane zostan kwestie
zwizane z tworzeniem programw wielowtkowych. W ramach tej czci ksiki
naley tylko wspomnie, e istniej modyfikatory, ktre mona, a czasami trzeba wykorzystywa w czasie tworzenia programw podzielonych na kilka wtkw wykonywanych w tym samym czasie (wspbienie). Jednym z takich sw jest volatile.
Modyfikator ten stosuje si wycznie w stosunku do pl. Oznacza on, e pole moe
by modyfikowane w kadym momencie i w kadym fragmencie kodu, nawet jeli
nie wynika to z samej jego treci. Jeli pole oznaczone jest sowem volatile, kompilator, nawet jeli wykonuje optymalizacj, uwzgldnia moliwo jego modyfikacji
z zewntrz. Fragment kodu, w ktrym stosowanie tego modyfikatora jest szczeglnie wskazane, pokazany jest na listingu 2.108.
Listing 2.108. Kod, w ktrym powinno si uy modyfikatora volatile
public void show() {
volatile current = 1;
while (true) {
System.err.println(current);
// tu wstrzymanie wykonania programu
// na okrelony czas
}
}

current jest polem klasy, do ktrej naley metoda show, widocznym przez wtki wykonywane wspbienie do tej metody. Gdyby pole to byo zadeklarowane bez modyfikatora volatile, wtedy kompilator w ramach optymalizacji kodu mgby zamieni
wywoanie:
System.err.println(current);

na:
System.err.println(1);

Ta zamiana wyniknaby z tego, e warto current jest niezmienna w czasie wykonywania ptli. Umieszczenie w deklaracji pola opisywanego modyfikatora spowoduje,
e kompilator uwzgldni moliwo, e midzy kolejnymi wywoaniami wywietlania
wartoci current moe si ona zmieni, mimo i nie wynika to z kodu wewntrz ptli.

2.9.7. Metody synchronizowane


Kolejny modyfikator stosowany wycznie w programowaniu wspbienym to synchronized. Nie wdajc si w szczegy (zaprezentuj je dalej), powiem tylko, e w czasie
wykonywania si metody synchronizowanej inne wtki odwoujce si do obiektu,
w ktrym jest ona zadeklarowana, zostaj wstrzymane do momentu zakoczenia jej
dziaania. W praktyce oznacza to, e synchronizowana metoda zostanie wykonana
w caoci, jako jedna porcja kodu. Ma to znaczenie na przykad w przypadku wykonywania

114

Java. Programowanie obiektowe

skomplikowanych i dugotrwaych oblicze, dla ktrych przechowujemy kilka wynikw porednich. Wyobramy sobie, e program analityczny wyznacza korelacj cech
X i Y wedug schematu pokazanego na listingu 2.109.
Listing 2.109. Przykadowy kod wymagajcy synchronizacji
WyznaczWariancjeX();
WyznaczWariancjeY();
WyznaczKowarianceXY();
WyznaczKorelacjaXY();

Kada z uywanych i wywoywanych w tym fragmencie metod zapisuje wynik swojego dziaania, ktry jest wynikiem porednim tych oblicze w polu dostpnym dla
innych wtkw. Gdyby dziaanie zaprezentowanego fragmentu zostao przerwane
przez inny wtek, ktry odwoywaby si zarwno do wynikw porednich, jak i kocowych mogoby si okaza, e cz wynikw pochodzi jeszcze ze starych wylicze, a cz ju z nowych. Efekt byby tragiczny dla poprawnoci dziaania wtku
wykorzystujcego te wyniki. Aby temu zapobiec, powinnimy zadeklarowa metod
zawierajc przedstawiony wczeniej fragment jako synchronizowan. Da to gwarancj, e wykona si ona caa w jednej porcji, co zapewni spjno wynikw porednich
z kocowym.

2.9.8. Pola ulotne


Java daje moliwo zapisywania stanu obiektw w sposb umoliwiajcy ich przysze odtworzenie. Umoliwia to na przykad zawieszenie pracy programu w dowolnym momencie w celu pniejszego odtworzenia go w dokadnie takim samym miejscu. Zdarzaj si jednak sytuacje, kiedy dziaanie takie nie jest konieczne, a moe
nawet by niebezpieczne i szkodliwe. Moe to dotyczy przypadku, gdy przechowujemy w obiekcie porednie wartoci uatwiajce szybkie uwiarygodnienie hasa bd
deszyfracj wiadomoci. Zapisanie tych wartoci w sposb atwo dostpny mogoby
uatwi zamanie zabezpiecze, ktre inaczej byyby dostatecznie wiarygodne. Aby
mona byo zabezpieczy si przed tak sytuacj, w Javie istnieje specjalny modyfikator transient wyczajcy z zapisu to pole. W czasie zapisu obiektu na dysk pole
oznaczone tym modyfikatorem wypeniane jest wartoci pust (null), mimo e zawiera pewn warto. W czasie odczytu pole to jest wic niewypenione i musimy
zainicjowa je ponownie specjalnie skonstruowan w tym celu metod.

2.9.9. Metody rodzime


Specyficzne znaczenie ma modyfikator native. Umoliwia on wywoywanie funkcji
wewntrznych systemu operacyjnego. Standardowo program w Javie tumaczony jest
na specjalny pseudokod, ktry jest w swoim charakterze bardzo podobny do kodu
powszechnie stosowanych procesorw. Rnica midzy Jav a innymi powszechnymi
rozwizaniami jest taka, e w wikszoci przypadkw tumaczenie kodu rdowego
odbywa si z uyciem zasad obowizujcych konkretny procesor i konkretny system
operacyjny. Kod w Javie tumaczony jest dokadnie tak samo, jednak stosowane s

Rozdzia 2. Klasy i obiekty w Javie

115

zasady ustalone dla wirtualnego, a nie konkretnego docelowego procesora i systemu


operacyjnego. Poczenie tych dwch nierzeczywistych urzdze wspistnieje w wirtualnej maszynie Javy (JVM). Maszyna ta to nic innego jak aplikacja, ju dla konkretnego systemu operacyjnego i procesora, ktra umoliwia uruchomienie programu
wynikowego w Javie na dowolnym komputerze. W zwizku z takim rozwizaniem
program w Javie jest w trakcie dziaania na bieco tumaczony z wewntrznych instrukcji JVM na instrukcje procesora. Moe to w niektrych przypadkach spowolni
jego dziaanie. Aby temu zaradzi, mona zastosowa metody napisane w czystym
kodzie maszynowym konkretnego procesora. Czsto ma to zalet szybszego wykonania i uproszczenia dostpu do niektrych specyficznych funkcji systemu operacyjnego.
Wad jest konieczno pisania takich funkcji dla wszystkich rodzajw komputerw,
na ktrych ma pracowa nasz program. Peny opis znaczenia i moliwoci modyfikatora native znajduje si w specyfikacji JNI (Java Native Interface).
W apletach nie mona zastosowa takich funkcji z dwch powodw. Po pierwsze
nigdy nie wiadomo, do jakiego komputera zostanie zaadowana strona HTML, ktra
zawiera nasz aplet. Moe si okaza, e nie przewidzielimy uycia konkretnego systemu, co spowodowaoby, e aplet nie pracowaby poprawnie. Druga kwestia, waniejsza ze wzgldw bezpieczestwa uytkownika, to fakt, e metody w kodzie maszynowym mog mie nieograniczony dostp do zasobw komputera, na ktrym si
wykonuj. Bez wikszych problemw mogyby wic odczytywa bd zapisywa
plik na lokalnym dysku osoby przegldajcej strony internetowe. Takie rozwizanie jest
oczywicie nie do zaakceptowania przez wikszo serfujcych po internecie, zostao
wic zablokowane w apletach. Moim zdaniem, jeli nasz program w Javie zaczyna
wymaga funkcji natywnych, oznacza to, e zrezygnowalimy w nim z przenonoci
i uniwersalnoci na rzecz celw, ktre znacznie atwiej zrealizowa w innych rodowiskach typu RAD, jakimi s na przykad Delphi, Kylix, C++Builder czy VisualAge for C.

2.10. Podsumowanie
W rozdziale tym pokazaem rodki do tworzenia klas i obiektw w Javie, jednak samo pokazanie sposobu uywania jzyka jest niewystarczajce do tego, by osign
zadowalajce rezultaty. Dopiero trening czyni mistrza. Wychodzc z tego zaoenia,
w nastpnych rozdziaach zaprezentuj i wyjani kolejne waniejsze i mniej wane
kwestie zwizane programowaniem obiektowym ju na konkretnych przykadach i problemach, ktre pojawiaj si w czasie tworzenia apletw i programw w Javie.

116

Java. Programowanie obiektowe

You might also like