Überschreiben von Methoden

Überschreiben von Methoden

  • Häufig will eine Subklasse nicht exakt das Verhalten der Superklasse erben
  • Subklassen können daher Methoden der Superklasse durch eigenen Implementierungen ersetzen ⇒ überschreiben (overriding)
  • Die überschriebene Methode hat
    • denselben Namen
    • denselben Rückgabetyp
    • dieselbe Parameterliste
    • aber möglicherweise ein anderes Verhalten als die Methode aus der Superklasse

Beispiel: Überschreiben von Methoden

public class Mitarbeiter {

    public String name;
    public double gehalt;
    public Date geboren;

    public String getDetails() {
        return name + ", geb. am " + geboren +
                " hat ein Gehalt von " + gehalt;
    }
}
public class Manager extends Mitarbeiter {
    public String abteilung;

    public String getDetails() {
        return name + ", geb. am " + geburtsdatum +
                " hat ein Gehalt von " + gehalt +
                " und leitet die Abteilung " + abteilung;
    }
}
public class Geschaeftsfuehrer extends Manager {
    public boolean prokura = true;

    public String getDetails() {
        return name + ", geb. am " + geburtsdatum +
                " hat ein Gehalt von " + gehalt +
                " und leitet die Abteilung " + abteilung +
                " und hat Prokura " + prokura;
    }
}

Manager und Geschaeftsfuehrer überschreiben die getDetails()`-Methode von Mitarbeiter und passen sie an die jeweiligen Bedürfnisse der Klasse an.

Aufruf einer überschriebenen Methode

public class Manager extends Mitarbeiter {
    public String abteilung;

    public String getDetails() {
        return super.getDetails() +
                " und leitet die Abteilung " + abteilung;
    }
}

public class Geschaeftsfuehrer extends Manager {
    public boolean prokura = true;

    public String getDetails() {
        return super.getDetails() +
            " und hat Prokura " + prokura;
    }
}

Auch nachdem die Methode der Oberklasse überschrieben wurde, kann man noch auf sie zugreifen. Hierzu dient das Schlüsselwort super gefolgt von dem Namen der Methode aus der Oberklasse, die man rufen möchte.

Man kann mit super immer nur soweit die Vererbungshierarchie hinaufgehen, bis man das erste Mal auf die Methode mit dem genannten Namen trifft. Es ist nicht möglich darüber hinaus weiter nach oben zu navigieren, d. h. es gibt keine Möglichkeit aus einer Kette von mehrfach überschriebenen Methoden eine andere als die nächsthöhere aufzurufen.

Überschreiben und Zugriffskontrolle

Beim Überschreiben einer Methode kann die Sichtbarkeit nur gleich lassen oder erweitern

public class A {
    protected void methode() {}
}

public class B extends A {
    public void methode() {}
}
public class A {
    protected void methode() {}
}

public class B extends A {
    private void methode() {} // FEHLER!!
}

Sichtbarkeit wird eingeschränkt: Fehler zur Compile-Zeit.

Der Hintergrund dieser Regel wird sofort klar, wenn man sich mit der Polymorphie beschäftigt, die im nächsten Abschnitt erläutert wird.

Überschreiben und Rückgabetyp

Beim Überschreiben einer Methode kann man den Rückgabetyp nicht ändern

public class A {
    protected void methode() {}
}

public class B extends A {
    public void methode() {}
}
public class A {
    protected void methode() {}
}

public class B extends A {
    public int methode() {} // FEHLER!!
}

Seit Java 5.0 ist es möglich den Rückgabetyp einer überschriebenen Methode zu ändern solange der neue Typ eine Spezialisierung des überschriebene Typs ist. Man spricht hier von Methoden mit kovariantem Rückgabetyp (covariant return type).

Folgendes Beispiel ist korrekt für Java 5.0 und neuer, funktioniert aber nicht auf älteren Java-Releases:

class A {
}

class B extends A {
}

class C {
    A getFoo() {
        return new A();
    }
}

class D extends C {
    B getFoo() {
        return new B();
    }
}

Praxistipp: @Override verwenden

Überschriebene Methode mit @Override annotieren: Der Compiler stellt dann sicher, dass wirklich eine Methode aus der Oberklasse überschrieben wird

class A {

    public void method(Object o) {
        // ...
    }
}

class B extends A {

    @Override
    public void method(String o) { // FEHLER!!
        // ...
    }
}

Annotationen sind als Konzept an dieser Stelle zwar noch nicht bekannt, aber dieser Tipp lässt sich recht gut auch ohne detailliertes Wissen über Annotationen verwenden.

Setzt man diesen Trick konsequent ein, verhindert er, dass man aus Versehen eine Methode überlädt anstatt sie zu überschreiben oder in der Oberklasse den Namen oder die Signatur einer Methode ändert und damit die Methode der Unterklasse plötzlich gar keine vorhandene Methode der Superklasse mehr überschreibt. Da diese Art von Fehlern sehr subtil ist und damit schwer zu finden, hilft die @Override-Annotation diese zu vermeiden.

In dem hier dargestellten Beispiel stimmt die Signatur der Methode method in der Subklasse B nicht mit der Signatur der Methode in der Superklasse A überein, da in B der Parameter von Typ String in A aber vom Typ Object ist. Hierdurch wird die Methode gar nicht überschrieben, sondern überladen. Die Verwendung der @Override-Annotation sorgt dafür, dass ein Compiler-Fehler generiert wird und der Irrtum sofort entdeckt wird.

In vielen IDEs (z. B. Eclipse) kann man konfigurieren, dass die IDE automatisch beim Überschreiben einer Methode die Annotation dazu generiert bzw. warnt, wenn die Entwickler:innen sie bei einer überschriebenen Methode vergessen haben. Diese Feature sollte man auf jeden Fall nutzen.


Copyright © 2025 Thomas Smits