"Bună, Amigo!"
— Dar deja am salutat, Ellie!
"Hei, nu te certa cu mătușa ta. În secolul 31, dacă nu te-ai mai văzut pe cineva de mai bine de jumătate de oră, se obișnuiește să te saluti din nou. Așa că nu-mi da atitudinea ta!"
„Oricum, este timpul pentru un alt subiect interesant: reproducerea robotului!”
"O_O."
„Glumesc, noul subiect sunt clasele interioare anonime .”
„În Java, uneori există situații în care veți avea nevoie de o clasă pentru a moșteni mai multe clase. Deoarece Java nu acceptă moștenirea multiplă, au rezolvat această problemă folosind clase interne: în clasa noastră, declarăm o clasă interioară și facem moștenește orice clasă pe care trebuie să o moștenim. Iată un exemplu:"
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
TigerThread thread = new TigerThread();
thread.start();
}
class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
„Hai să cercetăm un alt exemplu:”
Avem nevoie de o subclasă a clasei Thread pentru a-i suprascrie metoda de rulare.”
„De aceea, în clasa Tiger am declarat clasa interioară TigerThread , care moștenește Thread și suprascrie metoda run.
„Pentru comoditate, am definit două metode în clasa Tiger: tigerRun și startTiger (care sunt analoge cu metodele de rulare și pornire ale Thread."
„În metoda tigerStart, creăm un obiect TigerThread și invocăm metoda lui start()”.
„JVM-ul va crea un fir nou care va începe să ruleze când este apelată metoda de rulare a lui TigerThread .”
„Această metodă apelează apoi metoda noastră de rulare : tigerRun ”.
„Am mai lucrat cu fire, așa că pare simplu.”
„Trebuie să denumim metodele tigerRun și tigerStart?”
„Nu, i-am fi putut chema să alerge și să înceapă, dar am vrut, de asemenea, să demonstrez că nu moștenim Thread. O explicație ar fi putut fi mai confuză.”
„OK. Atunci cred că am înțeles. Dar dacă tigerStart este apelat a doua oară, vom crea și vom începe un al doilea obiect Thread. Asta nu înseamnă că vom avea „un tigru care rulează pe două fire diferite”? "
"Ei bine, nu ești ascuțit! Ai dreptate și asta nu e bine. Hai să rescriem codul așa:"
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();
}
}
}
"Nu este perfect. Totuși nu poți apela de două ori o astfel de metodă. Dar de data aceasta, cel puțin nu vom crea un al doilea thread și nu vom face să pară că totul este în regulă."
"Așa este. A doua oară când pornește un Tigru, vei primi o excepție."
— Deja observ greşelile mai bine decât tine, Ellie!
"Da, te descurci grozav. Atunci hai să trecem la clasele interioare anonime."
„Rețineți câteva aspecte ale codului de mai sus:”
1) Am moștenit clasa Thread, dar nu am implementat practic niciun cod acolo. „A fost mai degrabă „trebuia să moștenim clasa Thread” decât „am moștenit-o pentru a o extinde”.
2) Va fi creat un singur obiect TigerThread.
Cu alte cuvinte, am scris o grămadă de cod doar pentru a suprascrie o metodă și a crea un obiect.
Îți amintești cum vorbeam despre invenția constructorilor?
Înainte de constructori | După constructori |
---|---|
|
|
„Văd că codul a devenit mai compact, dar nu prea înțeleg ce se întâmplă”.
„Putem combina patru lucruri într-unul singur:”
1) declararea unei clase derivate
2) depășirea metodei
3) declararea unei variabile
4) crearea unei instanțe a unei clase derivate.
„De fapt, ceea ce facem este să combinăm două operații: declararea unei clase derivate și crearea unei instanțe a acelei clase.”
Fără clasă anonimă | Cu clasa anonima |
---|---|
|
|
„Să explorăm din nou sintaxa:”
Thread thread = new Thread();
Thread thread = new Thread()
{
};
"Rețineți că nu definim pur și simplu o nouă clasă. Creăm o variabilă - există un punct și virgulă la sfârșit!"
„Și dacă vrem să suprascriem metoda de rulare, atunci trebuie să scriem asta:”
Thread thread = new Thread()
{
public void run()
{
System.out.println("new run-method");
}
};
"Te prinzi repede. Bravo!"
"Multumesc. Ce se intampla daca avem nevoie de alte metode care nu fac parte din clasa Thread?"
„Le poți scrie”.
„Deși anonim, aceasta este o clasă interioară cu drepturi depline:”
Cod Java | Descriere |
---|---|
|
Roșu: cod pentru crearea variabilei.
Verde: cod pentru crearea obiectului. Albastru: cod pentru clasa derivată anonimă. |
— O clasă interioară cu drepturi depline?
„Deci pot folosi variabilele clasei exterioare?”
"Absolut."
— Și pot să transmit ceva constructorului?
„Da, dar numai argumentele pentru constructorul superclasei:”
Clasă | Instanța unei clase interioare anonime |
---|---|
|
|
"Nu putem adăuga propriii parametri la constructorul altcuiva. Dar putem folosi variabilele clasei exterioare, ceea ce compensează frumos acest neajuns."
„Dacă mai trebuie să adaug alți parametri la constructor?”
„Atunci declarați o clasă interioară obișnuită (non-anonimă) și folosiți-o.”
— Corect, aproape că am uitat de asta.
"Ce se întâmplă dacă declar o variabilă statică? Ar face ca clasa anonimă să devină o clasă imbricată statică mai degrabă decât o clasă interioară? Cu alte cuvinte, îi va lipsi o referință la clasa exterioară?"
"Nu. Ar fi o clasă interioară anonimă. Uită-te la aceste exemple."
Cu clasa anonima | Fără clasă anonimă |
---|---|
|
|
|
|
"Înțeleg. Numai variabila statică ar fi statică, nu clasa."
"Da."
„De fapt, compilatorul creează clase interne pentru toate clasele interne anonime. Aceste clase sunt de obicei numite «1», «2», «3», etc."