Java Standard: Vererbung


Die sogenannte Vererbung ermöglicht es Informationen (Variablen) und Verhalten (Methoden / Operationen) weiterzugeben. Dies ist eine wesentliche Möglichkeit um Redundanz zu vermeiden. Die Erben fügen dann weitere Informationen und/oder Verhalten hinzu. Zwei Klassen stehen dabei zueinander als Superklasse (Erblasser) und Subklasse (Erbe) in Beziehung.

Vererbung ist ein zentrales Thema in der objektorientierten Programmierung (OOP) - siehe auch w:Objektorientierte Programmierung.

Erzeugen und Zerstören von Subklassen

Bearbeiten

Das Erzeugen und Zerstören von Subklassen erfolgt analog zu einer normalen Klasse. Intern werden jedoch auch die Standardkonstruktoren der jeweiligen Superklasse beim Erzeugen und analog die finalize Methode beim Zerstören aufgerufen. Dies ist wichtig, da wir die Informationen und das Verhalten der Superklasse verwenden. Evtl. Grundstellen der Informationen oder Aufräumarbeiten beim Zerstören unserer Instanz sind somit auch bei den ererbten Informationen notwendig.

Überschreiben von Methoden

Bearbeiten

In der Subklasse können Methoden der Basisklasse "überschrieben" werden. Damit wird der Inhalt der ursprünglichen Methode verändert.

 package org.wikibooks.de.javakurs.oo;
 public class MeineKlasse 
 {
   // Nun der Konstruktor
   public MeineKlasse () 
   {
   //...
   }
   //ursprüngliche Methode
   public methode()
   {
      System.out.println("Wir sind in der Basisklasse");
   }
 }
 
 public class MeineSubklasse extends MeineKlasse 
 {
   public methode()
   {
      System.out.println("Wir sind in der Subklasse");
   }
 }

Wird die methode()-Methode für ein Objekt des Typs MeineSubklasse aufgerufen, wird der Satz "Wir sind in der Subklasse" ausgegeben.

Überschriebene Methoden werden für die Anwendung der Laufzeit-Polymorphie in Java benötigt. Dabei werden Methoden erst zur Laufzeit (im Gegensatz zur Compile-Zeit) den Objekten zugeordnet.

Anmerkung: Im Deutschen wird das Verb "überschreiben" benutzt. Im Englischen heißt es jedoch "override", nicht "overwrite".

Mit dem JDK 1.6 / Java 6 sollte die zudem eine Annotation (Anmerkung) angebracht werden:

 ... 
 public class MeineSubklasse extends MeineKlasse 
 {
   @Override
   public methode()
   {
      System.out.println("Wir sind in der Subklasse");
   }
 }
 ...

Javaspezifische Implementierung

Bearbeiten

In Java sind alle Objekte von der Klasse Object abgeleitet. Object ist somit die Basisklasse von allen anderen Klassen. Alle Klassen sind Subklassen von Object.

Man leitet eine eigene Klasse von der Basisklasse durch extends ab:

  public class Beispiel extends Object
  {
    //...
  }

Als static-deklarierte Elemente gehören keinem Objekt an, sondern der Klasse (oder Schnittstelle), in der sie definiert sind. Das berühmteste Beispiel ist hier

 public static void main(String[] args)
 {
   //...
 }

Die main-Methode muss als static deklariert sein, da vor ihrem Aufrufen ja kein Objekt instanziiert sein kann.

Als static können sowohl Variablen als auch Methoden deklariert werden.

Da static-Methoden von allen Objekten unabhängig sind, haben sie Einschränkungen:

  • Es können aus ihnen heraus nur andere static-Methoden aufgerufen werden.
  • Sie können auch nur auf static-Variablen zugreifen.
  • static-Methoden und -Variablen können nicht mit this oder super angesprochen werden.

abstract

Bearbeiten

Als abstract-deklarierte Methoden werden in der Basisklasse nur deklariert. Die Definition findet dann in den Subklassen statt.

 abstract class BeispielKlasse 
 {
    abstract void schreibIrgendwas();
 }
 
 class BeispielSubklasse extends BeispielKlasse 
 {
    void schreibIrgendwas()
    {
       System.out.println("Irgendwas");
    }
 }

In der Basisklasse wird nur angegeben, dass die Methode existiert, aber nicht wie sie implementiert ist. Damit wird also zugesichert, dass jedes Objekt des Typs BeispielKlasse - und damit auch jedes Objekt einer davon abgeleiteten Klasse - die Methode schreibIrgendwas() besitzen muss.

In BeispielSubklasse muss die abstrakte Methode daher implementiert werden, ansonsten gibt es einen Compilerfehler. Wird eine abstrakte Methode in einer Unterklasse nicht implementiert, so muss diese Klasse selbst auch wiederum als abstract gekennzeichnet werden.

Generell muss jede Klasse, die mindestens eine abstrakte Methode enthält, auch selbst als abstrakt deklariert werden. Dies hat den Effekt, dass keine Objekte direkt von dieser Klasse erstellt werden können. Im obigen Beispiel wäre es also nicht zulässig, ein Objekt der Klasse BeispielKlasse mit

 new BeispielKlasse();

zu erzeugen.

Durch die Benutzung von final kann das Ableiten einer Klasse oder Überschreiben einer Methode verhindert werden.

 final class BeispielKlasse 
 {
    void schreibIrgendwas()
    {
      //...
    }
 }
 
 class BeispielSubklasse extends BeispielKlasse 
 {
   //...
 }

Das funktioniert nicht. Durch das final-Schlüsselwort kann von der Klasse Beispielklasse nicht abgeleitet werden.

 class BeispielKlasse 
 {
    final void schreibIrgendwas()
    {
      //...
    }
 }
 
 class BeispielSubklasse extends BeispielKlasse 
 {
    void schreibIrgendwas(){
      //...
    }
 }

Hier wird zwar die Subklasse erstellt, jedoch kann die Methode schreibIrgendwas() nicht überschrieben werden.

Um den Konstruktor der Basisklasse aufzurufen, wird die Methode super() verwendet. Sie wird im Konstruktor der Subklasse verwendet. super() wird benutzt, um private-Elemente der Basisklasse anzusprechen.

 class Beispiel extends Object
 {
    protected variable;
 
    Beispiel()
    {
       super();
       variable = 10;
    }  
 }

super() ruft hier den Konstruktor von Beispiel auf, und könnte somit private-Elemente manipulieren.

Als zweite Anwendungsmöglichkeit kann super im Zusammenhang mit einem Element der Basisklasse benutzt werden.

 super.methodeABC();
 super.variableXYZ;

Durch diese Aufrufe werden aus der Subklasse heraus die Methoden/ Variablen der Basisklasse aufgerufen.

Einfluss von Modifizierern auf die Vererbung

Bearbeiten

public und protected

Bearbeiten

Sowohl public- wie auch protected-Elemente werden an die abgeleitete Klasse vererbt. An ihrem public bzw. protected-Status ändert sich nichts.

 public methode();
 protected variable;

Private-Elemente werden nicht vererbt.

 private variable;

packagevisible

Bearbeiten

Dies ist der voreingestellte Modifizierer, der angewandet wird, wenn kein anderer Modifizierer angegeben wird. Durch ihn können nur Objekte aus dem gleichen Paket auf die Elemente zugreifen.

 class Beispielsklasse 
 {
   //...
 }

Er wird ohne Einschränkungen an die Subklasse vererbt.