Salt la conținutul principal
Modulul 3 · Lecția 2 din 26/14 în curs~15 min
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.

Java
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:

Java
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.

Java
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:

  1. Implementează toate metodele abstracte: în acest caz, subclasa poate fi o clasă normală (concretă) și poate fi instanțiată.
  2. Se declara abstract: dacă subclasa nu oferă o implementare pentru toate metodele abstracte moștenite, trebuie declarată și cu cuvântul cheie abstract.
Java
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

Exercițiu#java.m3.l2.e1
Încercări: 0Se încarcă…

Declarați o variabilă s de tip Shape și atribuiți-i un nou obiect Circle folosind polimorfismul.

Se încarcă editorul...
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

Exercițiu#java.m3.l2.e2
Încercări: 0Se încarcă…

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.

Se încarcă editorul...
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

Exercițiu#java.m3.l2.e3
Încercări: 0Se încarcă…

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().

Se încarcă editorul...
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