Java Tutorial #27

Vererbung in Java verständlich erklärt

2019-01-02 | credits: puhhha

Vererbung ist ein mächtiges Konzept, mit dem wir unsere Programme besser strukturieren und erweitern können. Wir werden uns hier Zeit nehmen, es so einfach wie möglich, aber auch genau zu erklären.

Wie funktioniert Vererbung?

Um den Sinn von Vererbung zu verstehen, schauen wir uns zuvor einmal folgende drei Klassen an:

class Hund {
    int alter;
    int groesse;

    public void geraeuschMachen(){
        System.out.println("Mache ein Geräusch...");
    }
}

class Katze {
    int alter;
    int groesse;

    public void geraeuschMachen(){
        System.out.println("Mache ein Geräusch...");
    }
}

class Eisbaer {
    int alter;
    int groesse;

    public void geraeuschMachen(){
        System.out.println("Mache ein Geräusch...");
    }
}

Erkennen Sie das Problem dieser Klassen? Richtig: Derselbe Code ist mehrfach geschrieben und damit verstoßen wir gegen eine der wichtigsten Regeln guten Programmierstils: Don't repeat yourself!

Genau hier setzt die Vererbung an: Wir prüfen, welche Member (Instanzvariablen und Methoden) die unterschiedlichen Klassen gemeinsam haben und schreiben daraus eine neue übergeordnete Klasse namens Saeugetier.

Die Klasse Saeugetier ist dann die Superklasse für die Unterklassen Hund, Katze, Eisbaer. Durch die Vererbung erhalten die Unterklassen alle Member der Oberklasse, sodass wir diese nicht mehr explizit im jeweiligen Klassencode der Unterklassen schreiben müssen.

So entsteht eine Vererbungshierarchie:

Java Vererbung

Wir sehen in der Grafik, dass die drei Unterklassen von der einen Oberklasse erben. In Java sagen wir dazu, dass eine Unterklasse die Oberklasse erweitert. Die Instanzvariablen alter und groesse sowie die Methode geraeuschMachen() sind nun auch in den Unterklassen verfügbar.

extends

Um eine Vererbungsbeziehung herzustellen, muss das Schlüsselwort extends (dt.: erweitert) und der Name der Oberklasse zur Klassendefinition der Unterklasse hinzugefügt werden:

public class Katze extends Saeugetier{ }

Die Unterklasse Katze erweitert jetzt die Oberklasse Saeugetier. Das heißt konkret: Auch wenn es im Code der Klasse Katze nicht explizit geschrieben steht, so besitzt sie durch Vererbung nun auch die Instanzvariablen alter und groesse sowie die Methode geraeuschMachen(). Für die übrigen abgeleiteten Klassen funktioniert das genauso.

Methoden überschreiben

Wenn wir nun Objekte der Unterklassen Hund, Katze, Eisbaer erstellen, können wir die von der Oberklasse geerbte Methode geraeuschMachen() ganz einfach auf diesen Objekten aufrufen:

public static void main(String[] args){

    new Hund().geraeuschMachen();  // Mache ein Geräusch...
    new Katze().geraeuschMachen(); // Mache ein Geräusch...
    new Eisbaer().geraeuschMachen(); // Mache ein Geräusch...

}

Allerdings ergibt sich jetzt ein neues Problem: In unserem Beispiel machen alle Tiere dasselbe Geräusch. Da nämlich die Unterklassen Hund, Katze und Eisbaer die Methode geraeuschMachen() so vererbt bekommen, wie sie in Saeugetier implementiert ist, ist der Code der Methode für alle Unterklassen identisch.

Das sollten wir ändern, damit unsere Tiere unterschiedliche Geräusche machen!

Dazu müssen wir die Methode geraeschMachen() in allen Unterklassen typspezifisch programmieren. Dies gelingt uns, indem wir die Methode in den Unterklassen überschreiben, damit jedes Tier sein eigenes Geräusch machen kann.

  • Eine Unterklasse kann die Implementierung einer geerbten Methode überschreiben. Beim Aufruf der Methode auf einem Objekt der Unterklasse wird dann die überschriebene Methode ausgeführt
  • Um eine Methode zu überschreiben, müssen wir in den Unterklassen die Methode noch einmal mit demselben Methoden-Kopf wie in der Oberklasse deklarieren, aber einen anderen Rumpf implementieren.
  • Wir sollten vor den zu überschreibenden Methoden noch die Annotation @Override setzen (Vorteile: Code ist besser lesbar und der Compiler stellt sicher, dass die Methode korrekt überschrieben wird). 

Für unsere Methode geraeuschMachen() sieht das dann so aus:

class Hund extends Saeugetier{
    @Override
    public void geraeuschMachen(){
        System.out.println("Wuff!");
    }
}

class Katze extends Saeugetier{
    @Override
    public void geraeuschMachen(){
        System.out.println("Miau!");
    }
}

class Eisbaer extends Saeugetier{
    @Override
    public void geraeuschMachen(){
        System.out.println("Bruumm!");
    }
}

Der Methodenkörper ist jetzt tierspezifisch ausprogrammiert. Beim Aufruf auf einem Objekt der Klassen Hund, Katze, Eisbaer werden die überschriebenen Methoden ausgeführt:

public static void main(String[] args){
    new Hund().geraeuschMachen(); // Wuff!!
    new Katze().geraeuschMachen();  // Miau!
    new Eisbaer().geraeuschMachen(); // Brumm!
}

Somit machen unterschiedliche Tiere auch unterschiedliche Geräusche :-)

Variablen bei Vererbung

Variablen werden in Java sehr unkompliziert vererbt, wie wir im folgenden Beispiel sehen:

class Saeugetier {
    int alter = 5;
}

class Katze extends Saeugetier {

}

class Playground {
   public static void main(String[] args){
       System.out.println(new Katze().alter); // 5
   }
}

Die in der Superklasse Saeugetier definierte Instanzvariable alter wird an die Unterklasse Katze vererbt. Damit verfügen auch Katzen-Objekte über ein Alter.

Werden private Instanzvariablen vererbt?

class Saeugetier {
    private int alter = 5;
}

class Katze extends Saeugetier { // Habe ich auch die Variable alter? }

Klare Antwort: Ja, private Instanzvariablen sind existent in der Unterklasse. Allerdings können wir bedingt durch den private Modifier nicht direkt auf sie zugreifen. Der Aufruf new Katze().alter; würde daher einen Compiler-Fehler verursachen.

Über einen Methodenaufruf erhalten wir aber indirekt Zugriff auf die private Instanzvariable. Hier der angepasste Code:

class Saeugetier {
    private int alter = 5;

    public int getAlter(){
        return alter;
    }
}


class Katze extends Saeugetier { }


class Playground {
   public static void main(String[] args){
       System.out.println(new Katze().getAlter()); // 5
   }
}
Werbung

Java lernen

Werde zum Java Profi!

PHP Lernen

Lerne serverbasierte Programmierung

JavaScript lernen

Skille dein Webcoding

FALCONBYTE.NET

Handmade with 🖤️

© 2018-2023 Stefan E. Heller

Impressum | Datenschutz | Changelog

Falconbyte Youtube Falconbyte GitHub facebook programmieren lernen twitter programmieren lernen discord programmieren lernen