
Witaj Amigo!
- Więc witaj już, Ellie!
Więc nie kłóć się z ciocią. W 31 wieku zwyczajowo wita się ponownie, jeśli nie widziało się osoby przez ponad pół godziny. Więc się nie pokazuj!
Tak więc nowym interesującym tematem jest reprodukcja robotów!
— O_O.
— Żartuję, nowym tematem są anonimowe klasy zagnieżdżone.
Czasami w Javie dochodzi do sytuacji, w której trzeba odziedziczyć klasę z kilku klas. Ponieważ wielokrotne dziedziczenie klas w Javie jest zabronione, problem ten rozwiązuje się za pomocą klas wewnętrznych: w klasie, której potrzebujemy, deklarujemy klasę wewnętrzną i dziedziczymy ją z klasy wymaganej. Przykład:
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
TigerThread thread = new TigerThread();
thread.start();
}
class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
Spójrzmy na ten przykład:
Potrzebujemy klasy, która dziedziczy po Thread, aby zastąpić jej metodę run.
W tym celu wewnątrz klasy Tiger zadeklarowaliśmy wewnętrzną klasę TigerThread , którą odziedziczyliśmy po Thread i której metoda run została nadpisana.
Dla naszej wygody zadeklarowaliśmy dwie metody w klasie Tiger (analogi metod run i start klasy Thread), metody tigerRun i startTiger .
W metodzie startTiger tworzymy obiekt typu TigerThread i wywołujemy na nim metodę start().
Maszyna Java utworzy wtedy nowy wątek, który rozpocznie się od wywołania metody run klasy TigerThread .
Ta metoda z kolei wywoła naszą metodę run , metodę tigerRun .
- Z nitkami miałem już do czynienia, więc wydaje się to niezbyt trudne.
Czy konieczne jest wywoływanie metod tigerRun i startTiger?
- Nie, można było wywołać run i start , ale chciałem dodatkowo pokazać, że nie dziedziczymy po Thread, poza tym można by się bardziej pogubić w moim wyjaśnieniu.
- OK. Wtedy wszystko wydaje się jasne. Dopiero przy drugim wywołaniu metody startTiger utworzymy kolejną klasę Thread i ją uruchomimy. Czy nie okaże się, że mamy „jeden tygrys pobiegnie w dwóch różnych wątkach”?
- Cóż, masz wielkie oczy. Zgadzam się, nie jest dobrze. Następnie przepiszmy kod w ten sposób:
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
thread.start();
}
private TigerThread thread = new TigerThread();
private class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
- Nie tak wspaniale. W każdym razie nie możesz wywołać tej metody dwukrotnie. Ale tym razem przynajmniej nie będziemy zakładać drugiego wątku i udawać, że wszystko jest w porządku.
- Zgadza się, uruchomiłem go po raz drugi, tygrys - zdobądź wyjątek.
„Widzę wszystkie błędy lepiej niż ty, Ellie!”
Dobrze zrobiony. Następnie przejdźmy do anonimowych klas wewnętrznych.
Zwróć uwagę na kilka aspektów powyższego kodu:
1) Odziedziczyliśmy po klasie Thread, ale tak naprawdę nie dodaliśmy tam żadnego kodu. Raczej musieliśmy dziedziczyć, a nie „odziedziczyliśmy w celu rozszerzenia klasy Thread”
2) Zostanie utworzony tylko jeden obiekt klasy TigerThread.
Te. aby nadpisać jedną metodę i stworzyć jeden obiekt, napisaliśmy całą masę kodu.
Pamiętasz, jak ci opowiadałem o wyglądzie konstruktorów?
Przed wynalazkiem | Po wynalazku |
---|---|
|
|
- Widzę, że kod stał się bardziej zwarty, ale nie do końca rozumiem, co się stało.
W jednym miejscu możemy połączyć cztery rzeczy:
1) deklaracja klasy pochodnej
2) przesłanianie metody
3) deklaracja zmiennej
4) utworzenie obiektu następcy klasy.
Tak naprawdę łączymy ze sobą dwie operacje – deklarację klasy pochodnej i tworzenie jej obiektu:
Brak anonimowej klasy | Korzystanie z anonimowej klasy |
---|---|
|
|
Spójrzmy jeszcze raz na składnię:
Thread thread = new Thread();
Thread thread = new Thread()
{
};
Uwaga - nie tylko deklarujemy nową klasę - tworzymy zmienną - średnik jest na końcu!
- A jeśli chcemy przesłonić metodę run, to musimy napisać tak:
Thread thread = new Thread()
{
public void run()
{
System.out.println("new run-method");
}
};
- Szybko łapiesz - brawo!
- Dziękuję. Co zrobić, jeśli potrzebuję więcej metod, których nie ma klasa Thread?
- Możesz je dodać.
To jest pełnoprawna klasa wewnętrzna, choć anonimowa:
Kod Javy | Opis |
---|---|
|
Kod tworzenia zmiennej jest zaznaczony na czerwono.
Zielony - tworzenie obiektów. Niebieski - kod anonimowego następcy klasy. |
- Pełnoprawna klasa wewnętrzna?
Te. Czy mogę również używać zewnętrznych zmiennych klasy?
- Tak oczywiście możesz.
- Czy mogę przekazać coś konstruktorowi?
— Tak, ale tylko parametry konstruktora klasy bazowej:
Klasa | Anonimowy obiekt klasy wewnętrznej |
---|---|
|
|
Nie możemy dodawać własnych parametrów do czyjegoś konstruktora. Ale możemy użyć zmiennych klasy zewnętrznej - to dość mocno rekompensuje tę wadę.
— A jeśli nadal naprawdę muszę dodać więcej parametrów do konstruktora?
„Następnie zadeklaruj normalną nieanonimową klasę wewnętrzną i użyj jej.
Rzeczywiście, prawie o tym zapomniałem.
A jeśli zadeklaruję zmienną statyczną, klasa anonimowa zostanie zagnieżdżona, a nie wewnętrzna - tj. bez odniesienia do klasy zewnętrznej?
- NIE. Będzie anonimowa klasa wewnętrzna. Zobacz przykłady:
Z anonimową klasą | Brak anonimowej klasy |
---|---|
|
|
|
|
- Jasne. Tylko zmienna staje się statyczna, a nie klasa.
- Tak.
W rzeczywistości podczas kompilacji kompilator generuje klasy wewnętrzne dla wszystkich anonimowych klas wewnętrznych. Takie klasy są zwykle nazywane „1”, „2”, „3” itp.
GO TO FULL VERSION