1. Prezentarea interfețelor
Astăzi este ziua ta pentru cunoaștere. Un alt subiect nou și interesant sunt interfețele.
Conceptul de interfață este copilul principiilor abstractizării și polimorfismului. O interfață este foarte asemănătoare cu o clasă abstractă, în care toate metodele sunt abstracte. Este declarată în același mod ca o clasă, dar folosim cuvântul interface
cheie.
interface Feline
{
void purr();
void meow();
void growl();
}
Iată câteva fapte utile despre interfețe:
1. Declararea unei interfețe
interface Drawable
{
void draw();
}
interface HasValue
{
int getValue();
}
- În loc de
class
cuvântul cheie, scrieminterface
. - Conține doar metode abstracte (nu scrieți
abstract
cuvântul cheie) - De fapt, interfețele au toate
public
metodele
O interfață poate moșteni doar interfețe. Dar o interfață poate avea mulți părinți. Un alt mod de a spune acest lucru este de a spune că Java are moștenire multiplă de interfețe. Exemple:
interface Piece extends Drawable, HasValue
{
int getX();
int getY();
}
3. Moștenirea claselor de la interfețe
O clasă poate moșteni mai multe interfețe (doar de la o clasă). Acest lucru se face folosind implements
cuvântul cheie. Exemplu:
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;
}
}
Clasa ChessItem este declarată abstractă: implementează toate metodele moștenite, cu excepția draw
. Cu alte cuvinte, ChessItem
clasa conține o metodă abstractă — draw()
.
Semnificația tehnică a cuvintelor cheie extends
și implements
este aceeași: ambele sunt moștenire. Distincția a fost făcută pentru a îmbunătăți lizibilitatea codului. De asemenea, spunem că clasele sunt moștenite (prin extends
) și interfețele sunt implementate (prin implements
)
4. Variabile
Iată cel mai important lucru: variabilele obișnuite nu pot fi declarate în interfețe (deși cele statice pot).
Dar de ce avem nevoie de interfețe? Când sunt folosite? Interfețele au două avantaje puternice față de clase:
2. Separarea „descrierea metodelor” de implementarea acestora.
Anterior, am spus că dacă doriți să permiteți ca metodele clasei dvs. să fie apelate din alte clase, atunci metodele dvs. trebuie să fie marcate cu cuvântul public
cheie. Dacă doriți ca unele dintre aceste metode să fie apelate numai din cadrul clasei dvs., trebuie să le marcați cu cuvântul private
cheie. Cu alte cuvinte, împărțim metodele clasei în două categorii: „pentru folosirea tuturor” și „numai pentru uzul nostru”.
Interfețele ajută la consolidarea acestei diviziuni în continuare. Vom face o „clasă specială pe care să o folosească toată lumea”, precum și o a doua clasă „doar pentru uzul nostru”, care va moșteni prima clasă. Iată aproximativ cum ar arăta:
Inainte de | După |
---|---|
|
|
|
|
Ne împărțim clasa în două: o interfață și o clasă care moștenește interfața . Și care este avantajul aici?
Multe clase diferite pot implementa (moșteni) aceeași interfață. Și fiecare poate avea propriul său comportament. De exemplu, ArrayList
LinkedList
sunt două implementări diferite ale List
interfeței.
Astfel, ascundem nu numai diferitele implementări, ci și clasa de implementare în sine (deoarece avem nevoie doar de interfața din cod). Acest lucru ne permite să fim foarte flexibili: chiar dacă programul rulează, putem înlocui un obiect cu altul, schimbând comportamentul unui obiect fără a afecta toate clasele care îl folosesc.
Aceasta este o tehnică foarte puternică atunci când este combinată cu polimorfismul. Deocamdată, este departe de a fi evident de ce ar trebui să faci asta. Mai întâi trebuie să întâlniți programe cu zeci sau sute de clase pentru a înțelege că interfețele vă pot face viața mult mai ușoară decât fără ele.
3. Moștenirea multiplă
În Java, toate clasele pot avea o singură clasă părinte. În alte limbaje de programare, clasele pot avea adesea mai multe clase părinte. Acest lucru este foarte convenabil, dar aduce și multe probleme.
Creatorii Java au ajuns la un compromis: au interzis moștenirea multiplă a claselor, dar au permis moștenirea multiplă a interfețelor. O interfață poate avea mai multe interfețe părinte. O clasă poate avea mai multe interfețe părinte, dar o singură clasă părinte.
De ce au interzis moștenirea multiplă a claselor, dar au permis moștenirea multiplă a interfețelor? Din cauza așa-numitei probleme de moștenire a diamantelor:
Când clasa B moștenește clasa A, nu știe nimic despre clasele C și D. Deci folosește variabilele clasei A așa cum crede de cuviință. Clasa C face același lucru: folosește variabilele clasei A, dar într-un mod diferit. Și toate acestea au ca rezultat un conflict în clasa D.
Să ne uităm la următorul exemplu simplu. Să presupunem că avem 3 clase:
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; }
}
Clasa Data stochează value
variabila. Clasa sa descendentă XCoordinate folosește acea variabilă pentru a stoca x
valoarea, iar YCoordinate
clasa descendentă o folosește pentru a stoca y
valoarea.
Și funcționează. Separat. Dar dacă vrem ca clasa XYCoordinates să moștenească atât clasele XCoordinate
cât și YCoordinate
, atunci obținem cod rupt. Această clasă va avea metodele claselor sale strămoși, dar nu vor funcționa corect, deoarece au același value variable
.
Dar pentru că interfețele nu pot avea variabile, ele nu pot avea acest tip de conflict. În consecință, este permisă moștenirea multiplă a interfețelor.
GO TO FULL VERSION