- Clasa părinte (superclass, supercalsă) – conține atribute și metode generale.
- Clasa copil (subclass, subclasă) – moștenește și poate extinde sau modifica comportamentul.
O subclasă moștenește toți membrii (câmpuri, metode și clase imbricate) din superclasa sa.
După cum am menționat la lecțiile anterioare în Java poate fi implementată doar moștenirea simplă, adică o clasă poate avea o singură superclasă sau clasă părinte.
Pentru a deriva o clasă se folosește cuvântul cheie extends în semnătura clasei copil, urmată de numele clasei părinte.
Să ne reamintim sintaxa generală de declarare a claselor:
[public][abstract][final] class nume_clasa[extends nume_super_clasă][implements Interfata1,Interfata2,...,InterfataN]{// atribute, metode, blocuri de cod, alte clase}
Sintaxa generală a moștenirii:
class SuperClasa{// variabile ale superclasei
// metode ale superclasei// metode ale superclasei}class SubClasa extends SuperClasa{// variabile ale subclasei
// metode ale subclasei}
Exemplu:
class Persoana {String nume;void afiseazaNume() {System.out.println("Nume: " + nume);}}class Student extends Persoana {int nota;void afiseazaNota() {System.out.println("Nota: " + nota);}}
public class Main{public static void main(String [] args){
Student s = new Student();s.nume = "Victoria";s.nota = 9;System.out.println(s.nume + " " + s.nota);
}}
public class Bicicleta {public int cadenta;//numărul de rotații a pedalelor pe minutpublic int angrenaj;public int viteza;public Bicicleta (int startCadenta, int startViteza, int startAngrenaj) {
angrenaj = startAngrenaj;cadenta = startCadenta;viteza = startViteza;
}public void setCadenta(int valoareNoua) {
cadenta = valoareNoua;
}public void setAngregaj(int valoareNoua) {
angrenaj = valoareNoua;
}public void aplicaFrina(int decrementare) {
viteza-= decrementare;
}public void maresteViteza(int incrementare) {
viteza += incrementare;
}}
O declarație de clasă pentru o clasă BicicletaMunte care este o subclasă de Bicicleta ar putea arăta astfel:
public class BicicletaMunte extends Bicicleta{
public int scaunGreutate;
public BicicletaMunte(int startGreuatate, int startCadenta, int startViteza, int startAngrenaj) {
super(startCadenta, startViteza, startAngrenaj);scaunGreutate = startGreuatate;
}public void setGreutate(int valoareNoua) {
scaunGreutate = valoareNoua;
}}
BicicletaMunte moștenește toți membri clasei Bicicleta, dar în același timp adaugă câmpul scaunGreutate și o metodă pentru a-i seta valoarea.
Rețineți!
- O subclasă moștenește toți membrii public și protected ai superclasei, indiferent de pachetul în care se află subclasa.
- Dacă subclasa se află în același pachet ca și părintele său, moștenește și membrii impliciți ai părintelui, adică cei care nu au nici un modificator de acces specificat.
- Puteți folosi membrii moșteniți așa cum sunt, îi puteți înlocui, îi puteți ascunde sau îi puteți completa cu membri noi:
- Câmpurile moștenite pot fi utilizate direct, la fel ca orice alte câmpuri.
- Puteți declara un câmp din subclasă cu același nume cu cel din superclasă, astfel ascunzându-l. (NU este recomandat).
- Puteți declara câmpuri noi în subclasă care nu sunt î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ă cu cea din superclasă, suprascriind-o astfel (overriding).
- Puteți scrie o nouă metodă statică în subclasă care are aceeași semnătură cu cea din superclasă, ascunzând-o astfel.
- Puteți declara metode noi în subclasă care nu sunt în superclasă.
- Puteți scrie un constructor de subclasă care invocă constructorul superclasei, fie implicit, fie folosind cuvântul cheie super.
- Nu puteți moșteni membrii privați ai clasei părinte. Totuși, dacă superclasa are metode public sau protected pentru accesarea câmpurilor sale private, acestea pot fi folosite și de subclasă.
1. pentru a referi o variabilă din clasa părinte: super.<nume_variabila>
class ClasaParinte{int num=100;}
class Subclasa extends ClasaParinte{int num=110;void printNumber(){System.out.println(super.num);}
public static void main(String args[]){Subclasa obj= new Subclasa ();obj.printNumber();}}
Atenție!
În cadrul moștenirii, o subclasă poate avea câmpuri cu același nume ca și clasa părinte. În acest caz, câmpul din clasa părinte este "ascuns" în favoarea câmpului cu același nume din subclasă. În codul de mai sus, subclasa Subclasa definește un câmp num care ascunde câmpul cu același nume din clasa părinte ClasaParinte. În metoda printNumber(), se folosește super.num pentru a accesa câmpul num din clasa părinte, care este ascuns în subclasă.
class ClasaParinte{int num=100;}
class Subclasa extends ClasaParinte{int num=110;void printNumber(){System.out.println(num);}
public static void main(String args[]){Subclasa obj= new Subclasa ();obj.printNumber();}}
Este important de reținut că utilizarea ascunderii câmpurilor poate duce la confuzie și este bine să fiți atenți la acest aspect. În mod obișnuit, este recomandat să evitați ascunderea câmpurilor, iar dacă este necesar, să fiți conștienți de acest lucru și să folosiți cu atenție super pentru a accesa câmpurile din clasa părinte.
2. pentru a forța apelarea unei metode din cadrul unei clase părinte:
class Persoanaa{protected String nume, prenume;protected int virsta;Persoanaa (String nume, String prenume, int virsta){
this.nume = nume;this.prenume = prenume;this.virsta = virsta;
}void detalii() {
System.out.print("Nume "+nume+" \nPrenume "+ prenume+" \nVirsta "+virsta);
}}class Elev extends Persoanaa{private String adresa;private double media;Elev(String nume, String prenume, int virsta, String adresa, double media){
super(nume, prenume, virsta);this.adresa = adresa;this.media = media;
}void detalii() {super.detalii();
System.out.println(" \nAdresa "+adresa+" \nMedia "+ media);
}}class Test_mostenire {public static void main(String[] args) {
Elev e1 = new Elev("Creanga", "Ion", 16, "str. Sarmizegetusa 48", 10);e1.detalii();
}}
Rețineți !
- Apelul super() trebuie să fie prima instrucțiune din corpul constructorului subclasei.
- Dacă constructorul subclasei nu va invoca explicit constructorul superclasei, compilatorul Java va însera automat un apel la constructorul clasei fără parametri.
- Dacă superclasa nu are constructor fără argumente veți obține eroare de compilare.
- O clasă declarată final nu poate fi extinsă.
1. Moștenirea permite dezvoltatorilor să reutilizeze codul deja scris într-o clasă de bază, fără a-l rescrie în mod repetat în clasele derivate. Acest lucru duce la o eficiență sporită în dezvoltarea software-ului, deoarece codul poate fi scris și testat o singură dată.
2. Moștenirea permite extinderea funcționalității claselor de bază prin adăugarea de metode sau atribute noi în clasele derivate. Astfel, este ușor să adăugați funcționalități noi fără a afecta funcționalitatea existentă.
3. Moștenirea contribuie la organizarea și structurarea codului. Clasele de bază pot reprezenta concepte generale sau abstracte, iar clasele derivate pot să ofere implementări specifice sau detaliate ale acestor concepte.
4. Moștenirea facilitează implementarea polimorfismului, unde obiecte de tipuri diferite pot fi tratați în mod uniform. Acest lucru duce la o mai mare flexibilitate și modularitate în proiectare.
5. Prin intermediul moștenirii, modificările într-o clasă de bază pot avea impact în toate clasele derivate. Astfel, întreținerea și actualizarea codului pot fi mai ușoare, deoarece modificările trebuie făcute doar într-un singur loc.
6. Moștenirea reflectă relații de tip "este-un" între clase. De exemplu, dacă avem o clasă de bază "Animal" și o clasă derivată "Câine", putem spune că "Câinele este un Animal".
Java 17 introduce câteva funcții noi și îmbunătățiri menite să îmbunătățească lizibilitatea codului, mentenața și securitatea?