Ce face Clase abstracte (abstract)
Cuvântul cheie abstract pus în fața unei clase spune că ea este doar o bază: new Angajat(...) nu compilează. Pus în fața unei metode, spune că metoda nu are corp (se termină cu ;) și că fiecare subclasă concretă trebuie să o implementeze.
Spre deosebire de o interfață, o clasă abstractă poate avea câmpuri cu stare, constructori și metode cu orice nivel de acces. Este potrivită când mai multe clase împart cod comun și diferă doar în câteva metode. O clasă poate extinde o singură clasă abstractă, dar poate implementa multe interfețe.
Un tipar des întâlnit este „metoda șablon”: clasa abstractă scrie pașii generali ai unui algoritm într-o metodă obișnuită și lasă detaliile pe seama metodelor abstracte.
Exemple
Exemplul 1: Bază comună, detalii în subclase
fluturas() este scrisă o singură dată în clasa abstractă și apelează salariu(), pe care fiecare subclasă o implementează altfel.
abstract class Angajat {
final String nume;
Angajat(String nume) {
this.nume = nume;
}
abstract double salariu();
String fluturas() {
return String.format("%-8s %-16s %9.2f lei", nume, getClass().getSimpleName(), salariu());
}
}
class AngajatLunar extends Angajat {
final double lunar;
AngajatLunar(String nume, double lunar) { super(nume); this.lunar = lunar; }
@Override
double salariu() { return lunar; }
}
class AngajatOrar extends Angajat {
final double tarif;
final int ore;
AngajatOrar(String nume, double tarif, int ore) { super(nume); this.tarif = tarif; this.ore = ore; }
@Override
double salariu() { return tarif * ore; }
}
public class Main {
public static void main(String[] args) {
Angajat[] statPlata = {
new AngajatLunar("Elena", 7800),
new AngajatOrar("George", 45.5, 120),
};
for (Angajat a : statPlata) {
System.out.println(a.fluturas());
}
}
}
Rezultat
Elena AngajatLunar 7800.00 lei
George AngajatOrar 5460.00 lei
Exemplul 2: Metoda șablon
Raport.genereaza() fixează ordinea pașilor. Subclasele aleg doar titlul și liniile. Metoda șablon este final, ca subclasele să nu-i schimbe ordinea.
import java.util.List;
abstract class Raport {
final void genereaza() {
System.out.println("=== " + titlu() + " ===");
for (String linie : linii()) {
System.out.println(" " + linie);
}
System.out.println("(" + linii().size() + " rânduri)");
}
abstract String titlu();
abstract List<String> linii();
}
class RaportVanzari extends Raport {
@Override String titlu() { return "Vânzări octombrie"; }
@Override List<String> linii() { return List.of("Iași: 12.400 lei", "Cluj: 15.150 lei"); }
}
class RaportStoc extends Raport {
@Override String titlu() { return "Stoc depozit"; }
@Override List<String> linii() { return List.of("făină: 40 saci", "zahăr: 25 saci", "ulei: 60 l"); }
}
public class Main {
public static void main(String[] args) {
new RaportVanzari().genereaza();
new RaportStoc().genereaza();
}
}
Rezultat
=== Vânzări octombrie ===
Iași: 12.400 lei
Cluj: 15.150 lei
(2 rânduri)
=== Stoc depozit ===
făină: 40 saci
zahăr: 25 saci
ulei: 60 l
(3 rânduri)
Greșeli frecvente
- Încerci să creezi obiectul direct:
new Angajat("Ion")dăAngajat is abstract; cannot be instantiated. - O subclasă uită o metodă abstractă:
AngajatOrar is not abstract and does not override abstract method salariu() in Angajat. - Scrii corp pentru o metodă abstractă (
abstract double salariu() { ... }):abstract methods cannot have a body. - Combini
abstractcufinalsauprivatepe aceeași metodă: nu are sens, pentru că metoda trebuie rescrisă, iar compilatorul refuză.
Comenzi înrudite
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.Moștenire (extends): Cu extends o clasă moștenește câmpurile și metodele altei clase și le poate extinde sau rescrie; Java permite o singură superclasă.Polimorfism: Polimorfismul înseamnă că același apel (f.arie()) execută metoda clasei reale a obiectului, chiar dacă variabila are tipul superclasei.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.