Direct naar de hoofdinhoud
Module 3 · Les 2 van 26/14 in de cursus~15 min
Modulelessen (2/2)

Polymorfisme en abstracte klassen

Polymorfisme en abstracte klassen zijn geavanceerde objectgeoriënteerde programmeerconcepten waarmee we flexibele, uitbreidbare code kunnen schrijven, onafhankelijk van specifieke implementaties.

Polymorfisme

De term polymorfisme (vele vormen) verwijst naar het vermogen om objecten van verschillende klassen te behandelen alsof ze tot een gemeenschappelijk type behoren. In Java kan een referentievariabele van een superklasse een verwijzing opslaan naar een object uit een van zijn subklassen.

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

Dankzij polymorfisme kunnen we dit doen:

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)

De beslissing over welke methode moet worden aangeroepen, wordt tijdens runtime genomen (Late Binding of dynamische verzending) op basis van het daadwerkelijke object, niet van het type referentievariabele.

Abstracte klassen (abstract)

Een abstracte klasse is een klasse die is gemarkeerd met het sleutelwoord abstract en die niet rechtstreeks kan worden geïnstantieerd (u kunt new MyAbstractClass() niet doen). Het dient als een "gedeeltelijke sjabloon" voor andere klassen.

Abstracte methoden

Een abstracte klasse kan abstracte methoden bevatten: methoden gedeclareerd zonder body (geen accolades en geen code), eindigend met een puntkomma. Niet-abstracte subklassen zijn vereist om alle overgeërfde abstracte methoden te implementeren.

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;
    }
}

Dynamische binding / Late binding

Hoe weet Java welke methode tijdens runtime moet worden uitgevoerd? Dit proces staat bekend als Late Binding (of dynamische binding). In tegenstelling tot overbelasting (die tijdens het compileren wordt opgelost), weet de compiler niet welke specifieke methode zal worden uitgevoerd. In plaats daarvan genereert het een algemene oproepinstructie. Tijdens runtime inspecteert de Java Virtual Machine (JVM) het daadwerkelijke object in het geheugen en roept de methode-implementatie aan die is gedefinieerd in de klasse van dat object.

Abstracte klassen en ontbrekende implementatie

Als een subklasse erft van een abstracte klasse, heeft deze twee opties:

  1. Implementeer alle abstracte methoden: in dit geval kan de subklasse een normale (concrete) klasse zijn en kan deze worden geïnstantieerd.
  2. Verklaar zichzelf abstract: als de subklasse geen implementatie biedt voor alle overgeërfde abstracte methoden, moet deze ook worden gedeclareerd met het sleutelwoord 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
}

Probeer het zelf

Oefening#java.m3.l2.e1
Pogingen: 0Laden…

Declareer een variabele s van het type Shape en wijs er een nieuw Circle-object aan toe met behulp van polymorfisme.

Editor laden…
Toon hint

Schrijf `Shape s = new Circle();` om het basistype als referentietype te gebruiken.

Oplossing beschikbaar na 3 pogingen

Oefening#java.m3.l2.e2
Pogingen: 0Laden…

Maak de klasse Shape abstract en voeg de abstracte methode double getArea() toe. Voltooi vervolgens Vierkant zodat het Shape uitbreidt en getArea() retourzijde * zijde implementeert.

Editor laden…
Toon hint

Declareer `public abstract double getArea();` in Shape. Voeg in Square `@Override public double getArea() { return side * side; }`.

Oplossing beschikbaar na 3 pogingen

Oefening#java.m3.l2.e3
Pogingen: 0Laden…

Declareer in de hoofdmethode een array van het type Shape[] met daarin een Circle-object met straal 2,0 en een Square-object met zijde 3,0. Gebruik vervolgens een lus (for of for-each) om het gebied van elke vorm af te drukken door de methode getArea() aan te roepen.

Editor laden…
Toon hint

Declareer de array met `Shape[] vormen = { new Circle(2.0), new Square(3.0) };` en loop er doorheen met `for (Shape s: vormen)` en print `s.getArea()`.

Oplossing beschikbaar na 3 pogingen