Ce face Moștenire (extends)
class Caine extends Animal spune că un câine „este un” animal. Subclasa Caine primește automat câmpurile și metodele (neprivate) ale superclasei Animal, adaugă ce are în plus și poate rescrie (override) metode, păstrând aceeași semnătură. Adnotarea @Override cere compilatorului să verifice că rescrierea este corectă.
O clasă are o singură superclasă directă: extends A, B nu există. Pentru a combina mai multe comportamente se folosesc interfețele (implements). Dacă nu scrii extends, clasa extinde automat java.lang.Object, rădăcina tuturor claselor.
Constructorii nu se moștenesc. Constructorul subclasei apelează întâi, explicit cu super(...) sau implicit, un constructor al superclasei. O clasă marcată final nu poate fi extinsă, iar una sealed își alege singură subclasele.
Exemple
Exemplul 1: O subclasă care moștenește și adaugă
Caine folosește metoda mananca moștenită, rescrie sunet și adaugă aduceMingea.
class Animal {
String nume;
Animal(String nume) {
this.nume = nume;
}
void mananca() {
System.out.println(nume + " mănâncă.");
}
String sunet() {
return "...";
}
}
class Caine extends Animal {
Caine(String nume) {
super(nume);
}
@Override
String sunet() {
return "Ham!";
}
void aduceMingea() {
System.out.println(nume + " aduce mingea.");
}
}
public class Main {
public static void main(String[] args) {
Caine rex = new Caine("Rex");
rex.mananca();
System.out.println(rex.nume + " face " + rex.sunet());
rex.aduceMingea();
Animal generic = new Animal("Animalul");
System.out.println(generic.nume + " face " + generic.sunet());
}
}
Rezultat
Rex mănâncă.
Rex face Ham!
Rex aduce mingea.
Animalul face ...
Exemplul 2: Lanțul de moștenire și ordinea constructorilor
La new Autobuz() rulează întâi constructorul lui Vehicul, apoi cel al lui Autovehicul, apoi cel al lui Autobuz: de la rădăcină spre frunză.
class Vehicul {
Vehicul() {
System.out.println("1. Vehicul");
}
}
class Autovehicul extends Vehicul {
Autovehicul() {
System.out.println("2. Autovehicul");
}
}
class Autobuz extends Autovehicul {
Autobuz() {
System.out.println("3. Autobuz");
}
}
public class Main {
public static void main(String[] args) {
Autobuz a = new Autobuz();
System.out.println("este Vehicul? " + (a instanceof Vehicul));
System.out.println("superclasa: " + Autobuz.class.getSuperclass().getSimpleName());
System.out.println("rădăcina: " + Vehicul.class.getSuperclass().getName());
}
}
Rezultat
1. Vehicul
2. Autovehicul
3. Autobuz
este Vehicul? true
superclasa: Autovehicul
rădăcina: java.lang.Object
Exemplul 3: O variabilă de tipul superclasei
Un Manager poate fi pus într-o variabilă Angajat. Metoda apelată este totuși cea rescrisă în Manager (polimorfism).
class Angajat {
final String nume;
final double salariuBaza;
Angajat(String nume, double salariuBaza) {
this.nume = nume;
this.salariuBaza = salariuBaza;
}
double salariu() {
return salariuBaza;
}
}
class Manager extends Angajat {
final double bonus;
Manager(String nume, double salariuBaza, double bonus) {
super(nume, salariuBaza);
this.bonus = bonus;
}
@Override
double salariu() {
return salariuBaza + bonus;
}
}
public class Main {
public static void main(String[] args) {
Angajat[] echipa = {
new Angajat("Ion", 6500),
new Manager("Carmen", 9000, 2500),
new Angajat("Vlad", 7200),
};
for (Angajat a : echipa) {
System.out.println(a.nume + ": " + a.salariu() + " lei");
}
}
}
Rezultat
Ion: 6500.0 lei
Carmen: 11500.0 lei
Vlad: 7200.0 lei
Greșeli frecvente
- Încerci moștenire multiplă:
class C extends A, Bdă'{' expected. Folosește o superclasă și interfețe. - Superclasa are doar un constructor cu parametri, iar subclasa nu apelează
super(...):constructor Animal in class Animal cannot be applied to given types. - Rescrii o metodă cu altă semnătură (alt tip de parametru) și obții de fapt o metodă nouă. Pune mereu
@Override: compilatorul semnalează greșeala. - Folosești moștenirea doar ca să refolosești cod, deși relația „este un” nu există (un
Cosnu este oArrayList). Adesea e mai bine ca obiectul să conțină o listă (compoziție).
Comenzi înrudite
super: super apelează constructorul superclasei sau versiunea din superclasă a unei metode rescrise.Polimorfism: Polimorfismul înseamnă că același apel (f.arie()) execută metoda clasei reale a obiectului, chiar dacă variabila are tipul superclasei.Interfețe (interface, implements): O interfață (interface) descrie ce metode trebuie să aibă o clasă; clasa o promite cu implements și poate implementa mai multe interfețe.Clase abstracte (abstract): O clasă abstract nu poate fi instanțiată direct; poate avea metode abstracte, pe care subclasele concrete sunt obligate să le scrie.final (și static final): final interzice schimbarea: o variabilă primește valoare o singură dată, o metodă nu poate fi rescrisă, o clasă nu poate fi extinsă.sealed, permits și non-sealed: O clasă sau interfață sealed își alege explicit subtipurile (permits); fiecare subtip este final, sealed sau non-sealed.