[ Pobierz całość w formacie PDF ]
Klasa anonimowa to klasa definiowana w miejscu, w którym tworzymy jej egzem-
plarz. Podobnie jak w przypadku klasycznych obiektów możemy je tworzyć w sposób
jawny, tak aby następnie były dostępne przez nazwę, bądz niejawny, na przykład
w czasie przekazywania ich do dalszego użycia wewnątrz innych klas. Najczęściej
wykorzystuje się tę drugą metodę, gdyż w naturalny sposób łączy się ona z cechami
klasy anonimowej. Tworzona jest na jednorazowy użytek za pomocą jednostkowej
definicji, która nigdy więcej w tej postaci nie będzie używana. Klasa anonimowa jest
tworzona według szablonu pokazanego na listingu 2.73.
Listing 2.73. Schemat tworzenia klasy anonimowej
new
KlasaBadzInterfejsBazowy
([lista argumentów])
{
ciaco klasy anonimowej
}
Jak widać, klasa anonimowa może zostać zdefiniowana wyłącznie w chwili tworzenia
jej egzemplarza, po wystąpieniu operatora new. Po tym operatorze musi wystąpić de-
finicja typu, po którym dziedziczy klasa anonimowa. Może to być nazwa klasy bazo-
wej bądz interfejsu. Jeśli podajemy nazwę interfejsu, domyślnie oznacza to, że klasa
anonimowa dziedziczy po klasie Object i implementuje wymieniony interfejs. Nie
jest możliwa implementacja większej liczby interfejsów niż jeden ani dziedziczenie
po klasie innej niż Object i jednoczesna implementacja interfejsu. Przykład klasycz-
nej 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
// obsługa zdarzenia e
}
}
);
add(b, null);
}
}
Wytłuszczony fragment to definicja klasy anonimowej dziedziczącej (niejawnie) po
klasie Object i implementującej interfejs ActionListener. Interfejs ten deklaruje ist-
nienie metody actionPerformed, która jest zdefiniowana w pokazanej klasie anoni-
mowej. Klasa ta będzie wykorzystana w obiekcie typu Button jako klasa nasłuchująca
zdarzeń pochodzących od przyciśniętego przycisku ekranowego. W chwili pojawienia
się tego zdarzenia wywoływana będzie metoda actionPerformed klasy podawanej
w metodzie addActionListener. W innych popularnych językach obiektowych, takich
jak Object Pascal czy C++, w takim wypadku przekazywalibyśmy adres procedury,
która byłaby wywoływana we właściwym momencie. Java jest tak mocno obiektowa,
że jest to niemożliwe. Zamiast tego przekazuje się adres obiektu, który w tym wypadku
jest nienazwanego typu. W związku z tym, że takie działanie wykonywane jest jedno-
razowo dla przyspieszenia tworzenia kodu, stosuje się klasę anonimową. Konstrukcja
taka nie wpływa na czytelność kodu, jednak przyjęła się wśród osób używających
Javy. Więcej na temat użycia klasy anonimowej i przykłady eliminacji anonimowości
znajdziesz w rozdziale 4. Programowanie sterowane zdarzeniami . Na listingu 2.75
zaprezentowałem jeszcze jeden przykład użycia klasy anonimowej. Pozornie nie wnosi
on nic nowego poza zaciemnieniem kodu. W praktyce umożliwia wyodrębnienie i zgru-
powanie kodu w jeden blok, podobnie jak podprogramy czy procedury lokalne w kla-
sycznym programowaniu strukturalnym.
Listing 2.75. Użycie klasy anonimowej do zgrupowania kodu
(new Object() {
// definicja pól
public void make() {
// działania w metodzie make
}
}).make();
Przedstawiona klasa anonimowa gromadzi pewne instrukcje wewnątrz metody make,
umożliwiając dostęp do lokalnych pól tej klasy. Stosowania takiej konstrukcji ma sens
w przypadku, gdy chcemy stworzyć silniejszą hermetyzację wewnątrz pojedynczej
metody.
Rozdział 2. f& Klasy i obiekty w Javie 87
2.5.2. Jawna klasa anonimowa
Najczęściej stosuje się klasy anonimowe, które nie posiadają nazwanych egzempla-
rzy. Nic jednak nie stoi na przeszkodzie temu, aby tworzyć klasy anonimowe z ich
użyciem. Fakt, że egzemplarz klasy jest nazwany, nie wpływa oczywiście na anoni-
mowość jej typu, co nie zawsze i nie przez wszystkich jest zrozumiałe. W praktyce
więc pokazany na listingu 2.76 przykład również zawiera klasę anonimową (wytłusz-
czony fragment jest deklaracją klasy dziedziczącej po Object i implementującej inter-
fejs 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
// obsługa zdarzenia e
}
};
public void init() {
b.addActionListener(a);
add(b, null);
}
}
Pokazany przykład ułatwi rozważania na temat sposobu rozszerzania klas za pomocą
mechanizmu klas anonimowych. Wprowadzając interfejsy, zwracałem uwagę na to,
że możemy stosować zmienne typu zgodnego z typem interfejsu. Tak właśnie stało
się w przykładzie pokazanym na listingu 2.76. Może on być użyty w miejscu, gdzie
wymagany jest taki typ (na przykład w metodzie addActionListener we wcześniej-
szym przykładzie), bądz jawnie, na przykład:
a.actionPerformed(null);
Ważne jest, aby struktura klasy anonimowej była znana kompilatorowi. Oznacza to,
że oprócz interfejsu klasa anonimowa może redefiniować istniejącą klasę. Nie ma
natomiast większego sensu wprowadzanie nowych metod do klasy anonimowej, gdyż
pózniej nie da się ich wykorzystać. Przykład klasy definiującej metodę make, której
nie da się następnie użyć, pokazany jest na listingu 2.77.
Listing 2.77. Niecelowe nazywanie egzemplarza klasy anonimowej
Object a = new Object() {
public void make() {
// ciało metody make
}
};
// błąd: make nie istnieje w klasie Object
a.make();
[ Pobierz całość w formacie PDF ]