Przejdź do głównej treści
eLearner.app
Moduł 3 · Lekcja 2 z 26/14 w kursie~15 min
Lekcje modułu (2/2)

Polimorfismo i Klasy Abstrakcyjne

Polimorfizm i klasy abstrakcyjne to zaawansowane pojęcia programowania obiektowego, które pozwalają na pisanie elastycznego, rozszerzalnego kodu niezależnego od konkretnych implementacji.

Polimorfizm

Termin polimorfizm (wielopostaciowość) odnosi się do możliwości traktowania obiektów różnych klas tak, jakby należały do wspólnego typu. W Javie zmienna typu klasy nadrzędnej może przechowywać referencję do obiektu dowolnej klasy podrzędnej.

Code
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");
    }
}

Dzięki polimorfizmowi możemy zrobić tak:

Code
Animal myAnimal1 = new Dog(); // Polimorfismo
Animal myAnimal2 = new Cat(); // Polimorfismo

myAnimal1.makeSound(); // Esegue il metodo di Dog (Woof)
myAnimal2.makeSound(); // Esegue il metodo di Cat (Miao)

Decyzja o tym, która metoda ma zostać wywołana, zapada w czasie wykonywania programu (późne wiązanie / Late Binding lub dynamic dispatch) na podstawie rzeczywistego obiektu, a nie typu zmiennej referencyjnej.

Klasy abstrakcyjne (abstract)

Klasa abstrakcyjna to klasa oznaczona słowem kluczowym abstract, której nie można bezpośrednio utworzyć (nie można wywołać new MyAbstractClass()). Służy jako "częściowy szablon" dla innych klas.

Metody abstrakcyjne

Klasa abstrakcyjna może zawierać metody abstrakcyjne: metody zadeklarowane bez ciała (bez nawiasów klamrowych i bez kodu), zakończone średnikiem. Nieabstrakcyjne klasy podrzędne są zobowiązane do zaimplementowania wszystkich odziedziczonych metod abstrakcyjnych.

Code
abstract class Shape {
    String color;

    // Metodo astratto (senza corpo)
    public abstract double getArea();
}

class Circle extends Shape {
    double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    // Obbligatorio implementare getArea
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

Dynamic Binding / Late Binding

Skąd Java wie, którą metodę wykonać w czasie wykonywania programu? Proces ten jest znany jako późne wiązanie (Late Binding lub Dynamic Binding). W przeciwieństwie do przeciążania (rozstrzyganego w czasie kompilacji), kompilator nie wie, która konkretna metoda zostanie wykonana. Zamiast tego generuje ogólną instrukcję wywołania. W czasie wykonywania wirtualna maszyna Javy (JVM) bada rzeczywisty obiekt w pamięci i wywołuje implementację metody zdefiniowaną w klasie tego obiektu.

Klasy abstrakcyjne i brak implementacji

Jeśli klasa podrzędna dziedziczy po klasie abstrakcyjnej, ma dwie opcje:

  1. Zaimplementować wszystkie metody abstrakcyjne: w tym przypadku klasa może być zwykłą klasą (konkretną) i można tworzyć jej instancje.
  2. Zadeklarować się jako abstrakcyjna: jeśli klasa podrzędna nie zapewnia implementacji wszystkich odziedziczonych metod abstrakcyjnych, musi sama zostać zadeklarowana ze słowem kluczowym abstract.
Code
abstract class Animal {
    public abstract void makeSound();
}

// Questa classe DEVE essere astratta perché non implementa makeSound()
abstract class Canine extends Animal {
    // Eredita makeSound() ma non lo implementa
}

Spróbuj sam

Ćwiczenie#java.m3.l2.e1
Próby: 0Ładowanie...

Zadeklaruj zmienną s typu Shape i przypisz jej nowy obiekt Circle za pomocą polimorfizmu.

Ładowanie edytora...
Pokaż wskazówkę

Wpisz `Shape s = new Circle();`, aby użyć typu bazowego jako typu referencji.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#java.m3.l2.e2
Próby: 0Ładowanie...

Uczyń klasę Shape abstrakcyjną i dodaj metodę abstrakcyjną double getArea(). Następnie uzupełnij klasę Square tak, aby rozszerzała Shape i implementowała getArea() zwracając side * side.

Ładowanie edytora...
Pokaż wskazówkę

Zadeklaruj `public abstract double getArea();` w Shape. W Square dodaj `@Override public double getArea() { return side * side; }`.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#java.m3.l2.e3
Próby: 0Ładowanie...

Zadeklaruj w metodzie main tablicę typu Shape[] zawierającą obiekt Circle o promieniu 2.0 i obiekt Square o boku 3.0. Następnie użyj pętli (for lub for-each), aby wypisać w konsoli pole powierzchni każdej figury, wywołując metodę getArea().

Ładowanie edytora...
Pokaż wskazówkę

Zadeklaruj tablicę za pomocą `Shape[] shapes = { new Circle(2.0), new Square(3.0) };` i przejdź po niej pętlą `for (Shape s : shapes)` wypisując `s.getArea()`.

Rozwiązanie dostępne po 3 próbach