Bună! În lecția de astăzi, vom continua să examinăm subiectul claselor imbricate. Acum este timpul pentru ultimul grup: clasele interioare anonime. Să revenim la diagrama noastră: Ca și orele locale despre care am vorbit în ultima lecție, clasele anonime sunt un fel de clasă interioară... Au și câteva asemănări și diferențe. Dar mai întâi, haideți să ne aprofundăm: de ce anume sunt numite „anonim”? Pentru a răspunde la aceasta, luați în considerare un exemplu simplu. Imaginați-vă că avem un program de bază care rulează constant și face ceva. Dorim să creăm un sistem de monitorizare pentru acest program, format din mai multe module. Un modul va urmări indicatorii generali de performanță și va menține un jurnal. Al doilea va înregistra și înregistra erorile într-un jurnal de erori. Al treilea va urmări activitățile suspecte: de exemplu, încercările de acces neautorizat și alte lucruri legate de securitate. Deoarece toate cele trei module ar trebui, în esență, să înceapă pur și simplu la începutul programului și să ruleze în fundal,
public interface MonitoringSystem {
public void startMonitoring();
}
3 clase concrete îl vor implementa:
public class GeneralIndicatorMonitoringModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
}
public class ErrorMonitoringModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor errors!");
}
}
public class SecurityModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor security!");
}
}
S-ar părea că totul este în ordine. Avem un sistem destul de coerent format din mai multe module. Fiecare dintre ei are propriul său comportament. Dacă avem nevoie de module noi, le putem adăuga, deoarece avem o interfață destul de ușor de implementat. Dar să ne gândim cum va funcționa sistemul nostru de monitorizare. Practic, trebuie doar să creăm 3 obiecte — GeneralIndicatorMonitoringModule
, ErrorMonitoringModule
, SecurityModule
— și să apelăm startMonitoring()
metoda pe fiecare dintre ele. Adică, tot ceea ce trebuie să facem este să creăm 3 obiecte și să apelăm o metodă pe ele.
public class Main {
public static void main(String[] args) {
GeneralIndicatorMonitoringModule generalModule = new GeneralIndicatorMonitoringModule();
ErrorMonitoringModule errorModule = new ErrorMonitoringModule();
SecurityModule securityModule = new SecurityModule();
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
}
}
Ieșire din consolă:
Starting to monitor general indicators!
Starting to monitor errors!
Starting to monitor security!
Și cu atât de puțină muncă, am scris întregul sistem: 3 clase și o interfață! Și toate acestea pentru a obține 6 linii de cod. Pe de altă parte, care sunt opțiunile noastre? Ei bine, nu este foarte tare că am scris aceste cursuri „o singură dată”. Dar cum putem remedia asta? Aici ne vin în ajutor clasele interioare anonime ! Iată cum arată în cazul nostru:
public class Main {
public static void main(String[] args) {
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
};
MonitoringSystem errorModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor errors!");
}
};
MonitoringSystem securityModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor security!");
}
};
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
}
}
Să ne dăm seama ce se întâmplă! Se pare că creăm un obiect de interfață:
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
};
Dar știm de mult că nu putem crea obiecte de interfață! Și așa este - este imposibil. De fapt, nu asta facem. Când scriem:
MonitoringSystem generalModule = new MonitoringSystem() {
};
următoarele se întâmplă în interiorul mașinii Java:
- Este creată o clasă Java fără nume care implementează
MonitoringSystem
interfața. - Când compilatorul vede o astfel de clasă, vă cere să implementați toate metodele interfeței
MonitoringSystem
(am făcut asta de 3 ori). - Un obiect al acestei clase este creat. Atenție la cod:
MonitoringSystem generalModule = new MonitoringSystem() {
};
Există un punct și virgulă la sfârșit! Este acolo cu un motiv. Declarăm simultan clasa (folosind acolade) și creăm o instanță a acesteia (folosind ();
). Fiecare dintre cele trei obiecte ale noastre suprascrie startMonitoring()
metoda în felul său. În cele din urmă, numim pur și simplu această metodă pe fiecare dintre ele:
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Ieșire din consolă:
Starting to monitor general indicators!
Starting to monitor errors!
Starting to monitor security!
Asta este! Ne-am atins obiectivul: am creat trei MonitoringSystem
obiecte, am depășit o metodă în trei moduri diferite și am numit-o de trei ori. Toate cele trei module au fost apelate cu succes și rulează. În același timp, structura programului nostru a devenit mult mai simplă! La urma urmei, clasele GeneralIndicatorMonitoringModule
, ErrorMonitoringModule
, și SecurityModule
pot fi acum eliminate complet din program! Pur și simplu nu avem nevoie de ele - am făcut o treabă grozavă fără ele. Dacă fiecare dintre clasele noastre anonime are nevoie de un comportament diferit, de exemplu propriile metode specifice pe care celelalte nu le au, le putem adăuga cu ușurință:
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
public void someSpecificMethod() {
System.out.println("Specific method only for the first module");
}
};
Documentația Oracle oferă o recomandare bună : „Folosiți [clase anonime] dacă trebuie să utilizați o clasă locală o singură dată”. O clasă anonimă este o clasă interioară cu drepturi depline. În consecință, are acces la variabilele clasei externe, inclusiv variabilele statice și private:
public class Main {
private static int currentErrorCount = 23;
public static void main(String[] args) {
MonitoringSystem errorModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor errors!");
}
public int getCurrentErrorCount() {
return currentErrorCount;
}
};
}
}
Au ceva în comun cu clasele locale: sunt vizibile doar în interiorul metodei în care sunt declarate. În exemplul de mai sus, orice încercare de a accesa obiectul errorModule
în afara main()
metodei va eșua. Și mai există o limitare importantă pe care clasele anonime o moștenesc de la „strămoșii” lor (clasele interne): o clasă anonimă nu poate conține variabile și metode statice . În exemplul de mai sus, dacă încercăm să facem getCurrentErrorCount()
metoda statică, compilatorul va genera o eroare:
// Error! Inner classes cannot have static declarations
public static int getCurrentErrorCount() {
return currentErrorCount;
}
Obținem același rezultat dacă încercăm să declarăm o variabilă statică:
MonitoringSystem errorModule = new MonitoringSystem() {
// Error! Inner classes cannot have static declarations!
static int staticInt = 10;
@Override
public void startMonitoring() {
System.out.println("Starting to monitor errors!");
}
};
Și lecția noastră de astăzi s-a încheiat! Dar chiar dacă am investigat ultimul grup de clase imbricate, încă nu am terminat acest subiect. Ce vom mai învăța despre clasele imbricate? Cu siguranță vei afla în curând! :)
GO TO FULL VERSION