Może to doprowadzić do dziwnego działania programu
lub nawet do jego zawieszenia się”.
Co zatem zrobić, jeśli w jakiś sposób powinniśmy „posprzątać” po sobie? Otóż w takich
sytuacjach musimy przejąć na siebie odpowiedzialność za stworzenie odpowiedniej metody i wywoływanie jej, zanim obiekt będzie mógł zostać usunięty z pamięci. Metodzie takiej można by nadać nazwę cleanUp()1.
W Java 2 SDK, w wersji 1.3, została wprowadzona metoda czasu wykonania programu
(ang. runtime method) o nazwie addShutdownHook(), do której można przekazać nie-
standardowy obiekt klasy potomnej klasy Thread. Jeśli wirtualna maszyna Javy będzie
mieć taką możliwość, to wykona wskazany kod podczas kończenia działania. Metoda ta
zazwyczaj działa poprawnie, chyba że wirtualna maszyna Javy zostanie nagle zamknię-
ta, na przykład poprzez sygnał kill w systemach Unix, sygnał KillProcess w 32-bitowych systemach Windows lub samoczynnie zakończy działanie ze względu na wykrycie nieprawidłowości w wewnętrznych strukturach danych.
1 W tłumaczeniu: „czystka” lub „porządek”.
8.6. Wykorzystanie klas wewnętrznych
263
A zatem, jakie wnioski? Co prawda nie ma co do tego żadnych gwarancji, niemniej jed-
nak jest spora szansa, że zarówno metody finalizujące, jak i wątki uruchamiane podczas zamykania JVM zostaną poprawnie wykonane.
8.6. Wykorzystanie klas wewnętrznych
Problem
Musimy napisać klasę prywatną lub klasę, która będzie wykorzystywana co najwyżej w jednej innej klasie.
Rozwiązanie
Należy stworzyć klasę „niepubliczną” lub klasę wewnętrzną.
Analiza
Klasę „niepubliczną” można stworzyć, umieszczając ją w pliku źródłowym innej klasy,
jednak poza jej definicją. Z kolei klasa wewnętrzna oznacza w terminologii języka Java klasę, zdefiniowaną wewnątrz innej klasy. Klasy wewnętrzne zostały spopularyzowane
w momencie wprowadzenia JDK 1.1, gdzie były wykorzystywane jako procedury ob-
sługi zdarzeń w aplikacjach o graficznym interfejsie użytkownika (patrz receptura 13.4), jednak możliwości ich zastosowania są znacznie szersze.
W rzeczywistości klasy wewnętrzne można tworzyć w kilku różnych sytuacjach. Jeśli kla-
sa wewnętrzna zostanie zdefiniowana jako członek pewnej klasy, to obiekty tej klasy we-wnętrznej będzie można tworzyć w dowolnym miejscu klasy, wewnątrz której została ona
zdefiniowana. Z kolei, jeśli klasa wewnętrzna zostanie zdefiniowana w metodzie, to bę-
dzie się można do niej odwoływać wyłącznie w tej metodzie. Klasy wewnętrzne mogą po-
siadać nazwy lub być klasami anonimowymi. Nazwane klasy wewnętrzne posiadają pełne
nazwy, których postać jest zależna od kompilatora; standardowa wirtualna maszyna Javy
umieszcza takie klasy w plikach o nazwach KlasaGlowna$KlasaWewnetrzna.class.
Nazwy anonimowych klas wewnętrznych także zależą od używanego kompilatora; stan-
dardowa wirtualna maszyna Javy po kompilacji umieszcza ich kod w plikach o nazwach
KlasaGlowna$1.class, KlasaGlowna$2.class i tak dalej.
Obiektów klas wewnętrznych nie można tworzyć w żadnych innych kontekstach; każda próba jawnego odwołania się do takiej klasy, na przykład do klasy InnaKasaGlowna$
KlasaWewnetrzna, zostanie wykryta w czasie kompilacji i spowoduje zgłoszenie błędu.
import java.awt.event.*;
import javax.swing.*;
public class AllClasses {
/** Klasa wewnętrzna, której można używać w dowolnym
264
Rozdział 8. Techniki obiektowe
* miejscu tego pliku.
*/
public class Data {
int x;
int y;
}
public void getResults() {
JButton b = new JButton("Kliknij mnie");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Dziękuję za naciśnięcie");
}
});
}
}
/** Klasy umieszczone w tym samym pliku co AllClasses, które
* jednak mogą być używane także w innych kontekstach
* (powodują jednak wygenerowanie ostrzeżenia).
*/
class AnotherClass {
// Metody i pola ...
}
8.7. Tworzenie metod zwrotnych
przy wykorzystaniu interfejsów
Problem
Chcielibyśmy stworzyć metodę zwrotną, czyli umożliwić innym klasom wywoływanie wskazanego fragmentu kodu.
Rozwiązanie