Lecții din modul (2/2)
Polimorfismul și clasele abstracte
Polimorfismul și clasele abstracte sunt concepte avansate de programare orientată pe obiecte care ne permit să scriem cod flexibil, extensibil, independent de implementările specifice.
Polimorfism
Termenul polimorfism (multe forme) se referă la capacitatea de a trata obiecte din clase diferite ca și cum ar aparține unui tip comun. În Java, o variabilă de referință superclasă poate stoca o referință la un obiect din oricare dintre subclasele sale.
class Animal {
public void makeSound() {
System.out.println("Verso...");
}
}
class Dog extends Animal {
public void makeSound() {
System.out.println("Woof");
}
}
class Cat extends Animal {
public void makeSound() {
System.out.println("Miao");
}
}Datorită polimorfismului, putem face acest lucru:
Animal myAnimal1 = new Dog(); // Polymorphism
Animal myAnimal2 = new Cat(); // Polymorphism
myAnimal1.makeSound(); // Executes Dog's method (Woof)
myAnimal2.makeSound(); // Executes Cat's method (Miao)Decizia asupra metodei de invocat este luată în timpul execuției (legare târzie sau expediere dinamică) pe baza obiectului real, nu a tipului variabilei de referință.
Clase de abstracte (abstract)
O clasă abstractă este o clasă marcată cu cuvântul cheie abstract care nu poate fi instanțiată direct (nu puteți face new MyAbstractClass()). Acesta servește ca un „șablon parțial” pentru alte clase.
Metode abstracte
O clasă abstractă poate conține metode abstracte: metode declarate fără corp (fără acolade și fără cod), care se termină cu punct și virgulă. Subclasele non-abstracte sunt necesare pentru a implementa toate metodele abstracte moștenite.
abstract class Shape {
String color;
// Abstract method (no body)
public abstract double getArea();
}
class Circle extends Shape {
double radius;
public Circle(double radius) {
this.radius = radius;
}
// Required to implement getArea
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}Legare dinamică / Legare tardivă
Cum știe Java ce metodă să execute în timpul execuției? Acest proces este cunoscut sub numele de Legarea târzie (sau Legarea dinamică). Spre deosebire de supraîncărcare (care este rezolvată în timpul compilării), compilatorul nu știe ce metodă specifică va fi executată. În schimb, generează o instrucțiune de apel generică. În timpul rulării, Java Virtual Machine (JVM) inspectează obiectul real din memorie și invocă implementarea metodei definită în clasa obiectului respectiv.
Clase abstracte și implementare lipsă
Dacă o subclasă moștenește dintr-o clasă abstractă, are două opțiuni:
- Implementează toate metodele abstracte: în acest caz, subclasa poate fi o clasă normală (concretă) și poate fi instanțiată.
- Se declara abstract: dacă subclasa nu oferă o implementare pentru toate metodele abstracte moștenite, trebuie declarată și cu cuvântul cheie
abstract.
abstract class Animal {
public abstract void makeSound();
}
// This class MUST be abstract because it does not implement makeSound()
abstract class Canine extends Animal {
// Inherits makeSound() but does not implement it
}Încercați-l singur
Declarați o variabilă s de tip Shape și atribuiți-i un nou obiect Circle folosind polimorfismul.
Afișează indiciu
Scrieți `Shape s = new Circle();` pentru a utiliza tipul de bază ca tip de referință.
Soluție disponibilă după 3 încercări
Faceți abstractă clasa Shape și adăugați metoda abstractă double getArea(). Apoi completați Square astfel încât să extindă Shape și să implementeze getArea() care returnează side * side.
Afișează indiciu
Declara `public abstract double getArea();` în Shape. În Square, adăugați `@Override public double getArea() { return side * side; }`.
Soluție disponibilă după 3 încercări
Declarați în metoda principală un tablou de tip Shape[] care conține un obiect Circle cu raza 2.0 și un obiect Square cu latura 3.0. Apoi, utilizați o buclă (for sau for-each) pentru a imprima zona fiecărei forme invocând metoda getArea().
Afișează indiciu
Declarați matricea cu `Shape[] shapes = { new Circle(2.0), new Square(3.0) };` și treceți prin el folosind `for (Shape s : shapes)` printing `s.getArea()`.
Soluție disponibilă după 3 încercări