1. Interfészek bemutatása
A mai nap a tudásé. Egy másik új és érdekes téma az interfészek.
Az interfész fogalma az absztrakció és a polimorfizmus elvének gyermeke. Az interfész nagyon hasonlít egy absztrakt osztályhoz, amelyben minden metódus absztrakt. Ugyanúgy van deklarálva, mint egy osztály, de mi a interface
kulcsszót használjuk.
interface Feline
{
void purr();
void meow();
void growl();
}
Íme néhány hasznos tény az interfészekről:
1. Interfész deklarálása
interface Drawable
{
void draw();
}
interface HasValue
{
int getValue();
}
- A kulcsszó helyett
class
azt írjuk, hogyinterface
. - Csak absztrakt metódusokat tartalmaz (ne írja be a
abstract
kulcsszót) - Valójában az interfészek minden
public
módszerrel rendelkeznek
Egy interfész csak interfészeket örökölhet. De egy felületnek sok szülője lehet. Ennek másik módja az, ha azt mondjuk, hogy a Java interfészek többszörös öröklődésével rendelkezik. Példák:
interface Piece extends Drawable, HasValue
{
int getX();
int getY();
}
3. Osztályok öröklése interfészekről
Egy osztály több interfészt is örökölhet (csak egy osztálytól). Ez a implements
kulcsszó használatával történik. Példa:
abstract class ChessItem implements Drawable, HasValue
{
private int x, y, value;
public int getValue()
{
return value;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
}
A ChessItem osztály absztraktnak mondható: az összes örökölt metódust megvalósítja, kivéve a draw
. Más szavakkal, az ChessItem
osztály egy absztrakt metódust tartalmaz - draw()
.
extends
A és a kulcsszavak technikai jelentése implements
ugyanaz: mindkettő öröklődés. A különbségtétel a kód olvashatóságának javítása érdekében történt. Azt is mondjuk, hogy az osztályok öröklődnek ( via extends
), az interfészek pedig implementáltak ( via implements
)
4. Változók
Itt van a legfontosabb: a közönséges változókat nem lehet az interfészekben deklarálni (bár a statikusakat igen).
De miért van szükségünk interfészekre? Mikor használják? Az interfészek két erős előnnyel rendelkeznek az osztályokkal szemben:
2. A "módszerek leírásának" elkülönítése a megvalósításuktól.
Korábban azt mondtuk, hogy ha engedélyezni szeretnéd, hogy osztályod metódusait más osztályokból hívják meg, akkor a metódusaidat meg kell jelölni a kulcsszóval public
. Ha azt szeretné, hogy egyes metódusok csak az osztályon belül legyenek meghívva, meg kell jelölnie őket a kulcsszóval private
. Más szóval, az osztály metódusait két kategóriába osztjuk: "mindenki használhatja" és "csak saját használatra".
Az interfészek tovább erősítik ezt a felosztást. Készítünk egy speciális „mindenki által használható osztályt”, valamint egy „csak saját használatra” második osztályt, amely örökli az első osztályt. Nagyjából így nézne ki:
Előtt | Után |
---|---|
|
|
|
|
Osztályunkat két részre osztottuk: egy interfészre és egy osztályra , amely örökli az interfészt . És mi az előnye itt?
Sok különböző osztály megvalósíthatja (örökölheti) ugyanazt az interfészt. És mindegyiknek megvan a maga viselkedése. Például ArrayList
LinkedList
az interfész két különböző megvalósítása List
.
Így nem csak a különféle implementációkat rejtjük el, hanem magát az implementációs osztályt is (hiszen csak az interfész kell a kódban). Ez lehetővé teszi számunkra, hogy nagyon rugalmasak legyünk: a program futása közben az egyik objektumot lecserélhetjük egy másikra, megváltoztatva az objektum viselkedését anélkül, hogy az összes osztályra hatással lenne, amely azt használja.
Ez egy nagyon erős technika, ha polimorfizmussal kombináljuk. Egyelőre közel sem nyilvánvaló, hogy miért kell ezt tennie. Először több tucat vagy több száz osztályt tartalmazó programokkal kell találkoznia, hogy megértse, az interfészek sokkal könnyebbé tehetik az életét, mint nélkülük.
3. Többszörös öröklődés
Java-ban minden osztálynak csak egy szülőosztálya lehet. Más programozási nyelvekben az osztályoknak gyakran több szülőosztálya is lehet. Ez nagyon kényelmes, de sok problémát is hoz.
A Java készítői kompromisszumra jutottak: megtiltották az osztályok többszörös öröklését, de engedélyezték az interfészek többszörös öröklését. Egy interfésznek több szülőfelülete is lehet. Egy osztálynak több szülőfelülete lehet, de csak egy szülőosztály.
Miért tiltották be az osztályok többszörös öröklését, de engedélyezték az interfészek többszörös öröklését? Az úgynevezett gyémánt öröklődési probléma miatt:
Amikor a B osztály örökli az A osztályt, nem tud semmit a C és D osztályokról. Tehát az A osztály változóit használja, ahogy jónak látja. A C osztály ugyanezt teszi: az A osztály változóit használja, de más módon. Mindez pedig konfliktust eredményez a D osztályban.
Nézzük a következő egyszerű példát. Tegyük fel, hogy 3 osztályunk van:
class Data
{
protected int value;
}
class XCoordinate extends Data
{
public void setX (int x) { value = x;}
public int getX () { return value;}
}
class YCoordinate extends Data
{
public void setY (int y) { value = y;}
public int getY () { return value; }
}
A Data osztály tárolja a value
változót. Az XCoordinate leszármazott osztálya ezt a változót használja az érték tárolására x
, a YCoordinate
leszármazott osztály pedig az érték tárolására y
.
És működik. Külön. De ha azt akarjuk, hogy az XYCoordinates osztály örökölje az XCoordinate
és YCoordinate
osztályokat is, akkor hibás kódot kapunk. Ennek az osztálynak az ősosztályainak metódusai lesznek, de nem fognak megfelelően működni, mert ugyanaz a value variable
.
De mivel az interfészek nem tartalmazhatnak változókat, nem lehetnek ilyen konfliktusaik. Ennek megfelelően az interfészek többszörös öröklése megengedett.
GO TO FULL VERSION