"A hozzáférésmódosítókról fogok beszélni . Már egyszer beszéltem róluk, de az ismétlés a tanulás egyik pillére."
Szabályozhatja a többi osztály hozzáférését (láthatóságát) az osztály metódusaihoz és változóihoz. Egy hozzáférés-módosító válaszol a „Ki férhet hozzá ehhez a módszerhez/változóhoz?” kérdésre. Minden metódushoz vagy változóhoz csak egy módosítót adhat meg.
1) « nyilvános » módosító.
A nyilvános módosítóval jelölt változó, metódus vagy osztály a program bármely pontjáról elérhető. Ez a nyitottság legmagasabb foka: nincsenek korlátozások.
2) « privát » módosító.
A privát módosítóval megjelölt változó, metódus vagy osztály csak abban az osztályban érhető el, ahol deklarálva van. A megjelölt metódus vagy változó el van rejtve az összes többi osztály elől. Ez a legmagasabb szintű adatvédelem: csak az osztályod férhet hozzá. Az ilyen módszerek nem öröklődnek, és nem bírálhatók felül. Ezenkívül nem érhetők el leszármazott osztályból.
3) « Alapértelmezett módosító».
Ha egy változó vagy metódus nincs megjelölve semmilyen módosítóval, akkor az "alapértelmezett" módosítóval megjelöltnek minősül. Az ezzel a módosítóval rendelkező változók és metódusok a csomag minden osztálya számára láthatók, ahol deklarálva vannak, és csak azok az osztályok. Ezt a módosítót " csomagnak " vagy " csomag privát hozzáférésnek" is nevezik , utalva arra, hogy a változókhoz és metódusokhoz való hozzáférés az osztályt tartalmazó teljes csomag számára nyitva áll.
4) " védett " módosító.
Ez a hozzáférési szint valamivel szélesebb, mint a csomag . A védett módosítóval megjelölt változó, metódus vagy osztály elérhető a csomagjából (mint például a "csomag"), és minden örökölt osztályból.
Ez a táblázat mindent elmagyaráz:
A láthatóság típusa | Kulcsszó | Hozzáférés | |||
---|---|---|---|---|---|
Osztályod | A csomagod | Leszármazott | Minden osztály | ||
Magán | magán | Igen | Nem | Nem | Nem |
Csomag | (nincs módosító) | Igen | Igen | Nem | Nem |
Védett | védett | Igen | Igen | Igen | Nem |
Nyilvános | nyilvános | Igen | Igen | Igen | Igen |
Van egy módja annak, hogy könnyen megjegyezze ezt a táblázatot. Képzeld el, hogy végrendeletet írsz. Az összes dolgait négy kategóriába sorolja. Ki használhatja a dolgaidat?
Kinek van hozzáférése | Módosító | Példa |
---|---|---|
Csak én | magán | Személyes napló |
Család | (nincs módosító) | Családi fotók |
Család és örökösök | védett | Családi birtok |
Mindenki | nyilvános | Emlékiratok |
"Nagyon olyan, mintha azt képzelnénk, hogy az ugyanabban a csomagban lévő osztályok egy család részei."
– Szeretnék néhány érdekes árnyalatot is elmesélni a módszerek felülbírálásával kapcsolatban.
1) Absztrakt módszer implicit megvalósítása.
Tegyük fel, hogy a következő kóddal rendelkezik:
class Cat
{
public String getName()
{
return "Oscar";
}
}
És úgy döntött, hogy létrehoz egy Tiger osztályt, amely örökli ezt az osztályt, és hozzáad egy felületet az új osztályhoz
class Cat
{
public String getName()
{
return "Oscar";
}
}
interface HasName
{
String getName();
int getWeight();
}
class Tiger extends Cat implements HasName
{
public int getWeight()
{
return 115;
}
}
Ha csak megvalósítja az összes hiányzó metódust, amelyet az IntelliJ IDEA javasol, később hosszú időt tölthet a hibakereséssel.
Kiderült, hogy a Tiger osztály rendelkezik egy Cat-től örökölt getName metódussal, amely a HasName felület getName metódusának megvalósítása lesz.
– Nem látok ebben semmi szörnyűt.
"Nem túl rossz, valószínű helye a hibáknak."
De lehet még rosszabb is:
interface HasWeight
{
int getValue();
}
interface HasSize
{
int getValue();
}
class Tiger extends Cat implements HasWeight, HasSize
{
public int getValue()
{
return 115;
}
}
Kiderült, hogy nem mindig lehet több interfészről örökölni. Pontosabban örökölheted őket, de nem tudod helyesen megvalósítani. Nézd meg a példát. Mindkét interfész megköveteli a getValue() metódus megvalósítását, de nem világos, hogy mit kell visszaadnia: a súlyt vagy a méretet? Ezzel elég kellemetlen foglalkozni.
"Egyetértek. Szeretnél egy metódust implementálni, de nem tudod. Már örököltél egy azonos nevű metódust az alaposztályból. Elromlott."
– De van egy jó hír.
2) A láthatóság bővítése. Ha egy típust örököl, bővítheti a metódus láthatóságát. Így néz ki:
Java kód | Leírás |
---|---|
|
|
|
A módszer láthatóságát bővítettük ról protected -ra public . |
Kód | Miért "legális" |
---|---|
|
Minden nagyszerű. Itt nem is tudjuk, hogy egy leszármazott osztályban bővült a láthatóság. |
|
Itt azt a módszert nevezzük, amelynek láthatósága kibővült.
Ha ez nem lehetséges, mindig deklarálhatnánk egy metódust a Tigerben: Más szóval, nem beszélünk semmilyen biztonsági megsértésről. |
|
Ha az alaposztály ( Cat ) metódusának meghívásához szükséges összes feltétel teljesül, akkor ezek minden bizonnyal teljesülnek a leszármazott típus ( Tiger ) metódus meghívásához. Mert a metódushívás korlátozásai gyengék voltak, nem erősek. |
– Nem vagyok benne biztos, hogy teljesen megértettem, de emlékezni fogok rá, hogy ez lehetséges.
3) A visszatérési típus szűkítése.
Felülírt metódusban a visszatérési típust módosíthatjuk szűkített referenciatípusra.
Java kód | Leírás |
---|---|
|
|
|
Felülírtuk a metódust getMyParent , és most egy objektumot ad vissza Tiger . |
Kód | Miért "legális" |
---|---|
|
Minden nagyszerű. Itt még azt sem tudjuk, hogy a getMyParent metódus visszatérési típusát kiszélesítették a leszármazott osztályban.
Hogyan működött és működik a „régi kód”. |
|
Itt azt a metódust nevezzük, amelynek visszatérési típusát szűkítettük.
Ha ez nem lehetséges, mindig deklarálhatnánk egy metódust a Tigerben: Más szóval, nincsenek biztonsági megsértések és/vagy típus-öntvény-sértések. |
|
És itt minden jól működik, bár a változók típusát kiterjesztettük az alaposztályra (Cat).
A felülbírálás miatt a megfelelő setMyParent metódus kerül meghívásra. A getMyParent metódus meghívásakor pedig nincs ok aggodalomra , mert a visszatérési érték, bár a Tiger osztályé, továbbra is gond nélkül hozzárendelhető az alaposztály (Cat) myParent változójához . A tigris objektumok biztonságosan tárolhatók Tigris változókban és Cat változókban is. |
"Igen. Értem. A metódusok felülbírálásakor tisztában kell lennie azzal, hogy mindez hogyan működik, ha objektumainkat olyan kódnak adjuk át, amely csak az alaposztályt tudja kezelni, és nem tud semmit az osztályunkról. "
"Pontosan! Akkor a nagy kérdés az, hogy miért nem tudjuk szűkíteni a visszatérési érték típusát egy metódus felülbírálásakor?"
"Nyilvánvaló, hogy ebben az esetben az alaposztály kódja leállna:"
Java kód | A probléma magyarázata |
---|---|
|
|
|
Túlterheltük a getMyParent metódust, és leszűkítettük a visszatérési értékének típusát.
Itt minden rendben van. |
|
Akkor ez a kód leáll.
A getMyParent metódus egy objektum bármely példányát visszaadhatja, mert valójában egy Tiger objektum hívja meg. És nincs csekkünk a feladat előtt. Így teljesen lehetséges, hogy a Cat-típusú myParent változó egy String hivatkozást fog tárolni. |
– Csodálatos példa, Amigo!
Java-ban a metódus meghívása előtt nincs ellenőrzés, hogy az objektum rendelkezik-e ilyen metódussal. Minden ellenőrzés futás közben történik. És egy hiányzó metódus [hipotetikus] hívása nagy valószínűséggel arra késztetné a programot, hogy megkíséreljen nem létező bájtkódot végrehajtani. Ez végül végzetes hibához vezetne, és az operációs rendszer erőszakkal bezárná a programot.
– Hú. Most már tudom.