02.01.19 12781 Views 14

credit: ©puhhha

Java Tutorial #27

Vererbung in Java verständlich erklärt

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.

Falconbyte unterstüzen

Betrieb und Pflege von Falconbyte brauchen viel Zeit und Geld. Um dir auch weiterhin hochwertigen Content anbieten zu können, kannst du uns sehr gerne mit einem kleinen "Trinkgeld" unterstützen.

Thema in Kurzform

  • Mit Vererbung ersparen wir uns doppelten Code.
  • Die Wartung des Programms wird deutlich vereinfacht: Eine Änderung des Codes in einer Oberklasse wirkt sich automatisch auf die Unterklassen aus.
  • Um eine Klasse von einer anderen erben zu lassen, verwenden wir das Schlüssekwort extends.

    Inhaltsverzeichnis

  1. Wie funktioniert Vererbung?
  2. extends
  3. Methoden überschreiben
  4. Variablen bei Vererbung
  5. Werden private Instanzvariablen vererbt?
  6. Übungen

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:

Vererbung Java erklärt

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

Übungen

einfach

Überschreibe die Methode printInfos() der Superklasse Car in der Unterklasse Ferrari so, dass sowohl der Wert der Instanzvariablen horsePower als auch model auf der Konsole angezeigt werden:

class Car {
    int horsePower;

    public void printInfos(){
        System.out.println(horsePower);
    }
}

class Ferrari extends Car{

    String model;

    public Ferrari(int hp, String model){
        horsePower = hp;
        this.model = model;
    }
}
Lösung ein-/ausblenden

mittel

Wieviele Compiler-Fehler sind im folgenden Code?

class Car {

    public void action1(){
        System.out.println("I drive fast");
    }

    public void action2(String c){
        System.out.println("The color is " + c);
    }

}


class Ferrari extends Car{

    public void action1(int x){
        System.out.println("Driving fast at " + x + " km/h");
    }

    public String action2(String c){
        System.out.println("The color is " + c);
        return c;
    }
}

A. 1
B. 2
C. 3
D. Keiner. Der Code ist sauber.

Lösung ein-/ausblenden

schwer

Sieh dir folgende Vererbungshierarchie an. Welche Aussage dazu ist richtig?

Vererbung Java Übungen

A. new Testarossa().methodX(); ruft methodX() aus der Klasse Car auf.
B. new California().methodX(); verursacht einen Compiler-Fehler.
C. new California().methodX(); ruft methodX() aus der Klasse Car auf.
D. new Ferrari().methodX(); verursacht einen Compiler-Fehler.
E. new Audi().methodX(); ruft methodX() aus der Klasse Car auf.

Lösung ein-/ausblenden

Konstruktoren bei Vererbung

Trainieren Sie ihre Konstruktoren-Skills

Primitive Datentypen

Am Ende des Kapitels werden Sie wissen, wie Primitive Datentypen korrekt eingesetzt werden.

Vererbung einfach erklärt

Lernen Sie die Grundlagen der Vererbung in Java

FALCONBYTE.NET

Handmade with 🖤️

© 2018-2022 Stefan E. Heller

Impressum | Datenschutz | Changelog

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