04_Inheritance

Code-Dateien

DateinameAktion
CODECode_Fahrzeug.zipDownload
CODECode_Fenster.zipDownload
CODECode_Mitarbeiter.zipDownload
CODECode_Mitarbeiter_Teil1.zipDownload
CODECode_Mitarbeiter_Teil2.zipDownload
CODECode_Student.zipDownload

Videos

DateinameAktion
VIDEOVideo_Bauernhof_DAbspielen
VIDEOVideo_Fahrzeug_Teil1_DAbspielen
VIDEOVideo_Fenster_DAbspielen
VIDEOVideo_Mitarbeiter_Teil1_DAbspielen
VIDEOVideo_Mitarbeiter_Teil2_DAbspielen
VIDEOVideo_Student_DAbspielen

Lernmaterialien

Vererbung Inheritance

Ohne Vererbung

public class Fenster {
    private String  material;
    private double  preis;
    private boolean kippbar;
    private Haus    haus;

    public Fenster(String material, double preis, boolean kippbar) {
        setMaterial(material);
        setPreis(preis);
        setKippbar(kippbar);
    }

    public String getMaterial() {
        return material;
    }

    public void setMaterial(String material) {
        if ((material.equals("Alu") || material.equals("Holz") || material.equals("Kunststoff")) 
            this.material = material;
        else {
            System.out.println("Fehler: ungültiges Material!");
            this.material = "Alu";
        }
    }
public class Dachfenster {
    private String  material;
    private double  preis;
    private boolean kippbar;
    private Haus    haus;
    private boolean sonnenrollo;

    public Dachfenster(String material, double preis, boolean kippbar, boolean sonnenrollo) {
        setMaterial(material);
        setPreis(preis);
        setKippbar(kippbar);
        setSonnenrollo(sonnenrollo);
    }

    public String getMaterial() {
        return material;
    }

    public void setMaterial(String material) {
        if ((material.equals("Alu") || material.equals("Holz") || material.equals("Kunststoff")) 
            this.material = material;
        else {
            System.out.println("Fehler: ungültiges Material!");
            this.material = "Alu";
        }
    }

Ohne Vererbung musst man aus der Fenster Klasse alles noch einmal implemntieren in der Dachfenster Klasse.

Doppelte Implementierung:

  • Attribute

  • Konstruktor

  • Getter/Setter

  • toString()

Der Vorteil von Vererbung ist:
gemeinsamer Code wird nicht doppelt geschrieben, gewartet und getestet.


Mit Vererbung

Die Klasse Fenster ist die Basisklasse

public class Fenster {
    ...
}

Diese Klasse beschreibt allgemeine Eigenschaften, die jedes Fenster hat:

  • material

  • preis

  • kippbar

  • haus

und allgemeine Methoden wie:

  • getMaterial()

  • setMaterial()

  • getPreis()

  • setPreis()

  • toString()

Das ist also eine gute Vaterklasse oder Basisklasse.

Was bedeutet Vererbung hier?

Vererbung bedeutet:

Man erstellt eine neue Klasse, die auf Fenster aufbaut und alles von Fenster übernimmt.

Zum Beispiel:

  • Dachfenster ist auch ein Fenster

  • Panoramafenster ist auch ein Fenster

  • Kellerfenster ist auch ein Fenster

Diese speziellen Fenster sind auch Fenster, haben aber vielleicht noch zusätzliche Eigenschaften.

Vererbung Dachfenster

public class Dachfenster extends Fenster {
    private boolean sonnenrollo;

    public Dachfenster(String material, double preis, boolean kippbar, boolean sonnenrollo) {
        super(material, preis, kippbar);
        setSonnenrollo (sonnenrollo);
    }

    public boolean isSonnenrollo() {
        return sonnenrollo;
    }

    public void setSonnenrollo(boolean sonnenrollo) {
        this.sonnenrollo = sonnenrollo;
    }
}

Was passiert hier genau?

extends Fenster

public class Dachfenster extends Fenster

Das heißt:

Dachfenster erbt von Fenster.

Die Klasse Dachfenster bekommt dadurch automatisch (Geschenk):

  • Fenster(...)

  • getMaterial()

  • setMaterial()

  • getPreis()

  • setPreis()

  • isKippbar()

  • setKippbar()

  • getHaus()

  • setHaus()

  • toString() (zunächst einmal)

Also alle Methoden der Vaterklasse.

Auch die Eigenschaften werden von der Vaterklasse vererbt.

Warum kann man nicht direkt auf material oder preis zugreifen?

In deiner Basisklasse sind die Attribute:

private String material;
private double preis;
private boolean kippbar;
private Haus haus;

Sie sind also private.

Das bedeutet: Eine Unterklasse wie Dachfenster erbt zwar das Objektverhalten, darf aber auf diese Eigenschaften nicht direkt zugreifen.

Also nicht so:

material = "Holz";   // Fehler!
preis = 300;         // Fehler!

Sondern über die geerbten Setter und Getter:

setMaterial("Holz");
double p = getPreis();
001.png

super(...)

In deiner Klasse Fenster gibt es diesen Konstruktor:

public Fenster(String material, double preis, boolean kippbar) {
    setMaterial(material);
    setPreis(preis);
    setKippbar(kippbar);
}

Wenn Dachfenster von Fenster erbt, dann müssen diese geerbten Eigenschaften auch initialisiert werden.

Der Aufruf des Konstruktors der Vaterklasse erfolgt über:

super(material, preis, kippbar);

Das ruft den Konstruktor der Oberklasse Fenster auf.

public class Dachfenster extends Fenster {
    private boolean sonnenrollo;

    public Dachfenster(String material, double preis, boolean kippbar, boolean sonnenrollo) {
        super(material, preis, kippbar);
        setSonnenrollo (sonnenrollo);
    }
002.png

Also:

  • super(...) legt ein neues Fenster an und verwendet den Fenster Konstruktor.

  • setSonnenrollo (sonnenrollo); initialisiert die zusätzlichen Eigenschaften von Dachfenster.

Somit bedeutet super(...) Vaterklasse.


Test

public class Test {
    public static void main(String[] args) {
        Dachfenster df = new Dachfenster("Holz", 450.0, true, true);

        System.out.println(df.getMaterial());
        System.out.println(df.getPreis());
        System.out.println(df.isKippbar());
        System.out.println(df.isSonnenrollo());
        df.setPreis(750);
        df.setSonnenrollo(false);
        System.out.println(df.toString());
               //Es fehlt die Eigenschaft Sonnenrollo
    }
}

Hier sieht man:

Dachfenster hat eigene Methoden wie:

  • isSonnenrollo()
  • setSonnenrollo(...)

und geerbte Methoden aus Fenster wie:

  • getMaterial()

  • getPreis()

  • isKippbar()


Methoden überschreiben

toString()

Eine Unterklasse kann Methoden der Oberklasse anpassen.

Zum Beispiel toString():

public class Fenster {
    ...

    @Override
    public String toString() {
        if (kippbar)
            return "Fenster: " + material + "   " + preis + " EUR kippbar";
        else
            return "Fenster: " + material + "   " + preis + " EUR nicht kippbar";
    }
}
Dachfenster df = new Dachfenster("Alu", 899, false, true);
System.out.println(df);

Ausgabe:
Fenster: Alu   899 EUR nicht kippbar

Es fehlt bei Dachfenster die Ausgabe der Eigenschaft sonnenrollo.

public class Dachfenster {
    ...

    @Override
    public String toString() {
        if (sonnenrollo == true)
            return super.toString() + " mit Sonnenrollo";
        else
            return super.toString() + " ohne Sonnenrollo";
    }

Bedeutung:

  • super.toString() verwendet die Ausgabe aus Fenster

  • danach wird die Zusatzinformation von Dachfenster ergänzt

Dachfenster df = new Dachfenster("Alu", 899, false, true);
System.out.println(df);

Ausgabe:
Fenster: Alu   899 EUR nicht kippbar mit Sonnenrollo

getPreisInklEinbau()

Der Einbau bei einem “normalen” Fenster kostet 800 Euro.

public class Fenster {
    ...

    public double getPreisInklEinbau() {
        return preis + 800;
    }

Der Einbau bei einem Dachfenster kostet 9000 Euro. Zusätzlich werden für den Einbau der Sonnenrollo 600 Euro verrechnet.

public class Dachfenster extends Fenster {
    ...

    @Override
    public double getPreisInklEinbau() {
        if (sonnenrollo)
            return getPreis() + 9000 + 600;
        else
            return getPreis() + 9000;
    }
}

abstract

Ausgehend von der Basisklasse Fenster kann man folgende Fenster herstellen:

1. Dachfenster

Zusätzliche Eigenschaften:

  • sonnenrollo : boolean

2. Panoramafenster

Zusätzliche Eigenschaften:

  • breite : double

  • hoehe : double

  • dreifachverglasung : boolean

3. Kellerfenster

Zusätzliche Eigenschaften:

  • einbruchsicher : boolean

  • lichtschacht : boolean

4. Schiebefenster

Zusätzliche Eigenschaften:

  • anzahlFluegel : int

  • schieneAusAluminium : boolean

5. Rundfenster

Zusätzliche Eigenschaften:

  • radius : double

  • festverglast : boolean

6. Sicherheitsfenster

Zusätzliche Eigenschaften:

  • sicherheitsstufe : int

  • panzerglas : boolean

7. Schallschutzfenster

Zusätzliche Eigenschaften:

  • schallschutzklasse : int

  • dezibelReduktion : double

8. Energiesparfenster

Zusätzliche Eigenschaften:

  • uWert : double

  • dreifachverglasung : boolean

  • waermeschutzbeschichtung : boolean

9. Balkonfenster

Zusätzliche Eigenschaften:

  • tuergriffMitSchloss : boolean

  • bodentief : boolean

10. SmartFenster

Zusätzliche Eigenschaften:

  • elektrischSteuerbar : boolean

  • regensensor : boolean

  • verdunkelbar : boolean

11. NormalesFenster

Keine zusätzlichen Eigenschaften.

Somit gibt es eigentlich kein Fenster sondern nur die oben genannten!

Eine abstract class ist eine unvollständige Klasse, von der keine Instanz (new Fenster(...)) erstellt werden kann.

Sie dient als gemeinsame Oberklasse für andere Klassen, aber von ihr selbst können keine Objekte erzeugt werden.

Das heißt:

Fenster f = new Fenster(...);

wäre nicht erlaubt, wenn Fenster als abstract definiert ist.

Man verwendet eine abstrakte Klasse, wenn man sagen möchte:

  • Es gibt gemeinsame Eigenschaften und Methoden für alle Unterklassen.

  • Aber die Oberklasse selbst ist eher ein allgemeines Konzept.

  • Nur konkrete Unterklassen sollen wirklich erzeugt werden.

So würde das aussehen

public abstract class Fenster {
    private String  material;
    private double  preis;
    private boolean kippbar;
    private Haus    haus;

Der einzige neue Teil ist:

public abstract class Fenster

Jetzt darf man kein Objekt (Instanz) mehr direkt erzeugen:

Fenster f = new Fenster("Holz", 300.0, true);   // Fehler

Aber Unterklassen darf man weiterhin erzeugen:

Dachfenster d = new Dachfenster("Holz", 450.0, true, true);

Die eigentlichen konkreten Typen (können Instanzen angelegt werden) sind dann zum Beispiel:

  • Dachfenster

  • Kellerfenster

  • Schiebefenster

Abstrakte Klassen können normale Methoden haben.

Abstrakte Methoden

Eine abstrakte Klasse kann zusätzlich abstrakte Methoden enthalten.

Das sind Methoden ohne Implementierung.

Sie geben nur vor, dass jede Unterklasse diese Methode selbst schreiben muss.

Beispiel:

public abstract class Fenster {
    private String material;
    private double preis;
    private boolean kippbar;

    public abstract double getPreisInklEinbau();
}

Hier ist: getPreisInklEinbau() eine abstrakte Methode.

Sie hat:

  • keinen Methodenkörper

  • nur einen Kopf

  • ein Semikolon statt { }

!!! Unterklasse muss diese Methode dann implementieren !!!

public class Dachfenster extends Fenster {
    private boolean sonnenrollo;

    @Override
    public double getPreisInklEinbau() {
        if (sonnenrollo)
            return getPreis() + 9000 + 600;
        else
            return getPreis() + 9000;
    }
}

Und z. B. noch:

public class Kellerfenster extends Fenster {
    private boolean einbruchsicher;

    @Override
    public double getPreisInklEinbau() {
        if (einbruchsicher)
            return getPreis() + 300 + 3000;
        else
            return getPreis() + 300;
    }
}

Die Oberklasse sagt:

Jede Unterklasse von Fenster muss die Methode getPreisInklEinbau() implementieren.

Dadurch ist eine einheitliche Struktur vorgegeben.