Szia! A mai órán folytatjuk a beágyazott osztályok témakörének vizsgálatát. Eljött az utolsó csoport ideje: névtelen belső osztályok. Térjünk vissza diagramunkhoz: A helyi osztályokhoz hasonlóan, amelyekről az előző leckében beszéltünk, az anonim osztályok is egyfajta belső osztályok... Több hasonlóság és különbség is van bennük. De először merüljünk el: miért is nevezik őket "névtelennek"? Ennek megválaszolásához vegyünk egy egyszerű példát. Képzeljük el, hogy van egy alapprogramunk, amely folyamatosan fut és csinál valamit. Ehhez a programhoz szeretnénk egy több modulból álló monitoring rendszert létrehozni. Az egyik modul a teljesítmény általános mutatóit követi, és naplót vezet. A második regisztrálja és rögzíti a hibákat egy hibanaplóban. A harmadik a gyanús tevékenységeket követi nyomon: például az illetéktelen hozzáférési kísérleteket és egyéb biztonsággal kapcsolatos dolgokat. Mivel lényegében mindhárom modulnak egyszerűen a program elején kell indulnia és a háttérben futnia,
public interface MonitoringSystem {
public void startMonitoring();
}
3 konkrét osztály fogja megvalósítani:
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!");
}
}
Úgy tűnik, minden rendben van. Van egy elég koherens rendszerünk, amely több modulból áll. Mindegyiküknek megvan a maga viselkedése. Ha új modulokra van szükségünk, akkor ezeket is felvehetjük, mert van egy elég egyszerűen megvalósítható felületünk. De gondoljuk át, hogyan fog működni a monitoring rendszerünk. Alapvetően csak 3 objektumot kell létrehoznunk – GeneralIndicatorMonitoringModule
, ErrorMonitoringModule
, SecurityModule
– és startMonitoring()
mindegyiken meghívnunk kell a metódust. Vagyis csak 3 objektumot kell létrehoznunk és 1 metódussal hívnunk meg rajtuk.
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();
}
}
Konzol kimenet:
Starting to monitor general indicators!
Starting to monitor errors!
Starting to monitor security!
És ilyen kevés munkával megírtuk a teljes rendszert: 3 osztály és egy felület! És mindezt 6 kódsor eléréséhez. Másrészt mik a lehetőségeink? Hát nem túl menő, hogy megírtuk ezeket az "egyszeri" órákat. De hogyan tudjuk ezt orvosolni? Itt anonim belső osztályok jönnek a segítségünkre! A mi esetünkben így néznek ki:
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();
}
}
Találjuk ki, mi a helyzet! Úgy tűnik, interfészobjektumot hozunk létre:
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
};
De már régóta tudjuk, hogy interfész objektumokat nem tudunk létrehozni! És ez így van – ez lehetetlen. Valójában nem ezt csináljuk. Amikor írunk:
MonitoringSystem generalModule = new MonitoringSystem() {
};
a következő történik a Java gépen belül:
- Létrejön egy névtelen Java osztály, amely megvalósítja az
MonitoringSystem
interfészt. - Amikor a fordító ilyen osztályt lát, megköveteli az interfész összes metódusának megvalósítását
MonitoringSystem
(ezt 3-szor csináltuk). - Ennek az osztálynak az egyik objektuma létrejön. Ügyeljen a kódra:
MonitoringSystem generalModule = new MonitoringSystem() {
};
Pontosvessző van a végén! Okkal van ott. Egyszerre deklaráljuk az osztályt (kapcsos kapcsos zárójelekkel), és létrehozunk belőle egy példányt (a segítségével ();
). Mindhárom objektumunk felülírja a startMonitoring()
módszert a maga módján. Végül egyszerűen hívjuk ezt a módszert mindegyiknél:
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Konzol kimenet:
Starting to monitor general indicators!
Starting to monitor errors!
Starting to monitor security!
Ez az! Elértük a célunkat: létrehoztunk három MonitoringSystem
objektumot, három különböző módon felülírtunk egy metódust, és háromszor meghívtuk. Mindhárom modul sikeresen meghívásra került, és fut. Ezzel együtt programunk felépítése is sokkal egyszerűbb lett! Végül is a GeneralIndicatorMonitoringModule
, ErrorMonitoringModule
, és SecurityModule
osztályok most teljesen eltávolíthatók a programból! Egyszerűen nincs szükségünk rájuk – nagyszerű munkát végeztünk nélkülük. Ha minden névtelen osztályunknak más viselkedésre van szüksége, például saját specifikus metódusaira, amelyekkel a többi nem rendelkezik, könnyen hozzáadhatjuk őket:
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");
}
};
Az Oracle dokumentációja egy jó javaslatot ad : "Használja a [névtelen osztályokat], ha csak egyszer kell helyi osztályt használnia." Az anonim osztály teljes értékű belső osztály. Ennek megfelelően hozzáfér a külső osztály változóihoz, beleértve a statikus és privát változókat is:
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;
}
};
}
}
Van bennük valami közös a helyi osztályokkal: csak azon a metóduson belül láthatóak, amelyben deklarálták őket. A fenti példában az errorModule
objektum metóduson kívüli elérésére tett kísérletek main()
sikertelenek. És van még egy fontos korlátozás, amelyet az anonim osztályok „őseiktől” (belső osztályaiktól) örökölnek: egy névtelen osztály nem tartalmazhat statikus változókat és metódusokat . A fenti példában, ha megpróbáljuk getCurrentErrorCount()
statikussá tenni a metódust, a fordító hibát generál:
// Error! Inner classes cannot have static declarations
public static int getCurrentErrorCount() {
return currentErrorCount;
}
Ugyanezt az eredményt kapjuk, ha statikus változót próbálunk deklarálni:
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!");
}
};
És a mai óránk véget ért! De annak ellenére, hogy megvizsgáltuk a beágyazott osztályok utolsó csoportját, még nem fejeztük be ezt a témát. Mit fogunk még megtudni a beágyazott osztályokról? Minden bizonnyal hamarosan megtudod! :)
GO TO FULL VERSION