Moștenire
În lecțiile precedente, ați văzut moștenirea menționată de mai multe ori. În limbajul Java, clasele pot fi derivate din alte clase, moștenind astfel câmpuri și metode din acele clase.
Cu excepția
Object
, care nu are superclasă, fiecare clasă are una și o singură superclasă directă (moștenire unică). În absența oricărei alte superclase explicite, fiecare clasă este implicit o subclasă a Object
. Clasele pot fi derivate din clase care sunt derivate din clase care sunt derivate din clase și așa mai departe și, în cele din urmă, derivat din cea mai înaltă clasă,
Object
. Se spune că o astfel de clasă provine din toate clasele din lanțul de moștenire care se întind înapoi la Object
. Ideea de moștenire este simplă, dar puternică: când doriți să creați o nouă clasă și există deja o clasă care include o parte din codul dorit, puteți obține noua dvs. clasă din clasa existentă . Procedând astfel, puteți reutiliza câmpurile și metodele clasei existente fără a fi nevoie să le scrieți (și să le depanați).
O subclasă moștenește toți membrii (câmpuri, metode și clase imbricate) din superclasa sa. Constructorii nu sunt membri, deci nu sunt moșteniți de subclase, dar constructorul superclasei poate fi invocat din subclasă.
Ierarhia clasei platformei Java
Object
, definită în pachetul java.lang
, definește și implementează un comportament comun tuturor claselor – inclusiv celor pe care le scrieți. În platforma Java, multe clase derivă direct din Object
, alte clase derivă din unele dintre acele clase și așa mai departe, formând o ierarhie de clase.
Toate clasele din platforma Java sunt descendenți ai obiectului
În partea de sus a ierarhiei, Object
este cel mai general dintre toate clasele. Clasele din partea de jos a ierarhiei oferă un comportament mai specializat.
Un exemplu de moștenire
Iată exemplul de cod pentru o posibilă implementare a unui Bicycle
clasă care a fost prezentată în lecția Clase și obiecte:
O declarație de clasă pentru o clasă MountainBike
care este o subclasă a Bicycle
ar putea arăta astfel:
public class MountainBike extends Bicycle { // the MountainBike subclass adds one field public int seatHeight; // the MountainBike subclass has one constructor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { super(startCadence, startSpeed, startGear); seatHeight = startHeight; } // the MountainBike subclass adds one method public void setHeight(int newValue) { seatHeight = newValue; } }
MountainBike
moștenește toate câmpurile și metodele Bicycle
și adaugă câmpul seatHeight
și o metodă pentru setarea acestuia. Cu excepția constructorului, este ca și cum ai fi scris o nouă clasă MountainBike
în întregime de la zero, cu patru câmpuri și cinci metode. Cu toate acestea, nu a trebuit să faceți toată munca. Acest lucru ar fi deosebit de valoros dacă metodele din clasa Bicycle
ar fi complexe și ar fi avut nevoie de timp substanțial pentru depanare.
Ce puteți face într-o subclasă
O subclasă moștenește toți membrii publici și protejați ai părintelui său, indiferent în ce pachet este subclasa. Dacă subclasa se află în același pachet cu părinte, moștenește, de asemenea, membrii pachetului-părinți ai părinților. Puteți utiliza membrii moșteniți ca atare, îi puteți înlocui, ascunde sau completați cu membri noi:
- Câmpurile moștenite pot să fie utilizat direct, la fel ca orice alte câmpuri.
- Puteți declara un câmp din subclasă cu același nume ca cel din superclasă, ascunzându-l astfel (nu este recomandat).
- Puteți declara câmpuri noi din subclasă care nu se află în superclasă.
- Metodele moștenite pot fi utilizate direct așa cum sunt.
- Puteți scrie o nouă metodă de instanță în subclasă care are aceeași semnătură ca cea din superclasă, anulând-o astfel.
- Puteți scrie o nouă metodă statică în subclasă care are aceeași semnătură ca cea din superclasă, ascunzându-o astfel.
- Puteți declara noi metode în subclasă care nu se află în superclasă.
- Puteți scrie un constructor de subclasă care invocă constructorul superclasei, fie implicit, fie utilizând cuvântul cheie
super
.
Următoarele secțiuni din această lecție se vor extinde pe aceste subiecte.
Membrii privați într-o superclasă
O subclasă nu moștenește private
membrii clasei sale părinte. Cu toate acestea, dacă superclasa are metode publice sau protejate pentru accesarea câmpurilor sale private, acestea pot fi folosite și de subclasă.
O clasă imbricată are acces la toți membrii privați ai clasei care o include – atât câmpuri, cât și metode. Prin urmare, o clasă cuibărită publică sau protejată moștenită de o subclasă are acces indirect la toți membrii privați ai superclasei.
Casting Objects
Am văzut că un obiect este din tipul de date al clasei de la care a fost instanțiată. De exemplu, dacă scriem
public MountainBike myBike = new MountainBike();
atunci myBike
este de tip MountainBike
.
MountainBike
provine din Bicycle
și Object
. Prin urmare, un MountainBike
este un Bicycle
și este, de asemenea, un Object
și poate fi folosit oriunde sunt solicitate obiecte Bicycle
sau Object
.
Reversul nu este neapărat adevărat: un Bicycle
poate fi un MountainBike
, dar nu este neapărat. În mod similar, un Object
poate fi Bicycle
sau un MountainBike
, dar nu este neapărat.
Distribuirea arată utilizarea unui obiect al unuia tip în loc de alt tip, printre obiectele permise de moștenire și implementări. De exemplu, dacă scriem
Object obj = new MountainBike();
atunci obj
este atât un Object
și un MountainBike
(până când obj
primește un alt obiect care nu este MountainBike
). Aceasta se numește casting implicit.
Dacă, pe de altă parte, scriem
MountainBike myBike = obj;
am face obțineți o eroare în timpul compilării, deoarece obj
nu este cunoscut de compilator ca fiind MountainBike
. Cu toate acestea, putem spune compilatorului că promitem să atribuim un MountainBike
lui obj
prin distribuire explicită:
MountainBike myBike = (MountainBike)obj;
Această distribuție introduce o verificare a timpului de execuție că obj
are atribuit un MountainBike
astfel încât compilatorul să poată presupune în siguranță că obj
este un MountainBike
. Dacă obj
nu este un MountainBike
în timpul rulării, se va arunca o excepție.
instanceof
. Acest lucru vă poate salva de la o eroare de rulare din cauza unei distribuții necorespunzătoare. De exemplu:
if (obj instanceof MountainBike) { MountainBike myBike = (MountainBike)obj;}
Aici operatorul instanceof
verifică dacă obj
se referă la un MountainBike
, astfel încât să putem face distribuția cu cunoștința că nu va exista nicio excepție de rulare.