Vererbung

Einstieg

Schon sehr früh lernen wir, Objekte in Beziehung zu setzen. Assoziationen bilden dabei die Hat-Beziehung zwischen Objekten ab: Ein Mensch hat Beine, der Fernseher hat eine Bildröhre. Neben der Assoziation von Objekten gibt es eine weitere Form der Beziehung, die Ist-eine-Art-von-Beziehung. Menschen und Affen sind Säugetiere. Eine Disko ist eine Unterkategorie eines Gebäudes. Konsumgerät ist der Oberbegriff für Fernseher, CD-Spieler, etc.. Die zentralen Mechanismen der Objektorientierung lassen sich erst nutzen, wenn Beziehungen zwischen Klassen möglich sind (Quelle: http://openbook.galileocomputing.de/).

Redundanz

In der Informatik wird Vererbung genutzt, um Redundanz zu vermeiden. Redundanz ist das mehrfache Vorhandensein ein und derselben Information. Beim Programmieren entstehen durch Redundanzen folgende Probleme

  • fehleranfällig bei Änderungen

  • größerer Aufwand bei Änderungen

  • erhöhter Speicherbedarf

Die Vererbung dient dazu, aufbauend auf existierenden Klassen neue zu schaffen und bereits vorhandene Strukturen und Verhalten wiederzuverwenden. Es gilt das Motto “do not repeat yourself”. Hierdurch wird Redundanz vermieden. Das grundlegende Konzept der Vererbung kann schon bei der UML-Modellierung (insbesondere im Klassendiagramm) berücksichtigt werden, um es dann in der Java-Programmierung umzusetzen.

Generalisierung und Spezialisierung

Eine wichtige Beziehung, die zwischen zwei Klassen bestehen kann, ist, dass eine Klasse als Unterklasse einer anderen Klasse eingestuft wird. Eine Unterklasse bezeichnet man als Spezialisierung einer Oberklasse. Eine Spezialisierung/Unterklasse erbt von der Generalisierung/Oberklasse (Quelle: http://openbook.galileocomputing.de/).

Die vererbende Klasse wird meist Superklasse (auch Basis-, Ober- oder Elternklasse) genannt, die erbende abgeleitete Klasse (auch Sub-, Unter- oder Kindklasse). Den Vorgang des Erbens nennt man meist Ableitung oder Spezialisierung, die Umkehrung hiervon Generalisierung.

Sichtbarkeit

Die abgeleitete Klasse bekommt sowohl alle Attribute als auch Methoden, die in der Superklasse mit der Sichtbarkeit public, protected oder keiner Sichtbarkeit versehen sind, vererbt. Alle Attribute und Methoden der Superklasse, die mit dem Schlüsselwort private gekennzeichnet sind, werden nicht vererbt. Die vererbten Methoden der Superklasse können auch in der Subklasse überladen oder sogar ersetzt (überschrieben) werden (Polymorphie). Beim Überschreiben von Methoden kann auch der Sichtbarkeitsmodifikator verändert werden, aber nur von gar keinem Modifikator zu protected oder public bzw. von protected zu public. Hier gilt die Regel: Das Attribut bzw. Methode darf nicht 'privater' sein als in der Superklasse.

Polymorphie

Polymorphie bedeutet "Vielgestaltigkeit." Im Bereich der Objektorientierung bezieht sich Polymorphie darauf, dass verschiedene Objekte bei Aufruf derselben Methode unterschiedliches Verhalten an den Tag legen können. Wird eine Methode von einer Superklasse an eine abgeleitete Klasse vererbt und dort mit der exakt identischen Signatur erneut implementiert, dann wird in der abgeleiteten Klasse das Verhalten dieser Methode überschrieben. Ruft man also diese Methode bei Objekten der abgeleiteten Klasse auf, verhalten sie sich anders als Methoden der Superklasse.

Vererbung im UML-Klassendiagramm

Anhand des folgenden Beispiels wird die Abbildung von Vererbung in einem UML-Klassendiagramm beschrieben.

Ein Friseursalon möchte sein Angebot von Dienstleistungen und Pflegeprodukten in der eingesetzten Terminverwaltungssoftware integrieren. Das Angebot wird folgendermaßen modelliert. Als Superklasse sind abstrakt Angebote vorgesehen. Die Klasse Angebot verfügt über drei private Attribute:

  • nummer

  • name

  • preis

Die Superklasse Angebot soll über die üblichen getter- und setter-Methoden verfügen. Außerdem wurde eine toString()-Methode modelliert.

Eine toString()-Methode dient üblicherweise dazu, alle Attribute in einem String zu verketten und diesen dann auszugeben. Für die Superklasse bedeutet dies, dass die Attribute nummer, name und preis zu einem String zusammengefasst werden und dieser zurückgegeben wird.

Die ableitenden Klassen Produkt und Dienstleistung erben alle öffentlichen (dargestellt durch ein Pluszeichen +) oder geschützten ("protected" dargestellt durch #) Attribute und Methoden von der Klasse Angebot. Das heißt, dass auch Instanzen der Klasse Dienstleistung über die folgenden öffentlichen Methoden verfügen:

  • getNummer():int

  • getName(): String

  • getPreis():double

  • setNummer(int n)

  • setName(Sting n)

  • setPreis(double p)

  • toString():String

Der direkte Zugriff auf die privaten Attribute

  • nummer: int

  • name: String

  • preis: double

ist nicht möglich. Private Attribute werden nicht vererbt. Über die öffentlichen getter- und setter-Methoden ist der Zugriff dennoch indirekt möglich. Die Datenstruktur ist also im Hintergrund vorhanden.

Die Methode toString() wird unter derselben Signatur in den erbenden Klassen Produkt und Dienstleistung erneut aufgeführt. Das bedeutet, dass diese Methoden in den jeweiligen erbenden Klassen überschrieben und erneut implementiert werden. Dieser Vorgang wird als Polymorphie bezeichnet.

Vererbung in Java

Im Java Programm werden die in UML dargestellten Vererbungsbeziehungen in Java Quelltext programmiert. Auch in Java wird zwischen einer Super- und einer abgeleiteten Klasse unterschieden. Die abgeleitete Klasse bekommt von ihrer Superklasse die öffentlichen (public) oder geschützten (protected) Attribute und Methoden vererbt. Des Weiteren werden abgeleitete Klassen um eigene Attribute und Methoden erweitert.

In Java gibt es keine Mehrfachvererbung. Alle Klassen gehen in Java auf eine globale Objekt-Klasse zurück und selbst benutzerdefinierte Klassen nutzen dessen Methoden und Eigenschaften (siehe nachfolgende Abbildung).

Soll eine Klasse von einer Superklasse erben, die nicht Bestandteil des Projektes oder der Standardbibliothek ist, muss die entsprechende Bibliothek importiert werden.

Syntax

Eine Vererbung in Java findet über das Schlüsselwort extends statt.

class Subklasse extends Superklasse {

Die Subklasse bezeichnet hier die Klasse, die etwas vererbt bekommt. Anschließend folgt das Schlüsselwort extends, welches die Vererbung der Superklasse einleitet. Es folgt der Name der Superklasse.

Sichtbarkeit

Die ableitende Klasse erbt alle öffentlichen (public) oder geschützten (protected) Attribute und Methoden von der Superklasse. Private (private) Methoden und Attribute werden nicht vererbt.

Über die öffentlichen Methoden wie z.B. die getter- und setter-Methoden ist der Zugriff auf private Attribute dennoch indirekt möglich. Die private Datenstruktur ist also auch bei der Vererbung im Hintergrund vorhanden. Die Attribute können jedoch nicht direkt aufgerufen werden.

super

super ist ein Schlüsselwort und ermöglicht den Zugriff auf die Superklasse von einer abgeleiteten Klasse. Dieser Zugriff ist z.B. nötig, wenn die aufzurufende Methode in der abgeleiteten Klasse durch Polymorphie überschrieben wurde.

Folgender Ausdruck ruft die toString()-Methode der Superklasse auf. Die Implementierung von toString() in der ableitenden Klasse bleibt dann unberücksichtigt.

super.toString()

Beispiel Java

Betrachten wir nun erneut das oben dargestellte Klassendiagramm. Die Klasse Angebot vererbt Attribute an die Klassen Produkt. Die Vererbung wird die durch das Schlüsselwort extends in der Klasse Produkt ausgelöst. Es folgt der Name der Superklasse Angebot. Hierdurch wird die Vererbung implementiert. In der Superklasse müssen keine Angaben gemacht werden.Die Klasse Produkt erbt alle öffentlichen (public) und geschützten (proteceted) Attribute der Klasse Angebot. In diesem Falle wird kein Attribut vererbt, da alle Attribute als privat deklariert wurden.

Die privaten Attribute der Klasse Angebot sind im Hintergrund auch in der Klasse Produkt vorhanden. Jedoch besteht in der Klasse Produkt keine Möglichkeit direkt auf diese zuzugreifen. Nur über die vererbten getter- und setter-Methoden ist ein ein Ändern oder Auslesen möglich.

Die Klasse Produkt erbt alle öffentlichen (public) und geschützten (proteceted) Methoden der Klasse Angebot. In diesem Fall sind alle Methoden öffentlich (public) und stehen damit auch in der Klasse Produkt zur Verfügung.

Der Konstruktor der Klasse Produkt nutzt eine geerbte Methode setNummer um einen Standardwert zu setzen.

Die Methode toString() der erbenden Klasse Produkt überschreibt die toString() Methode der vererbenden Superklasse Angebot (Polymorphie). Hier für die ursprüngliche Implementierung mit super aufgerufen und fehlende Felder werden ergänzt.

// Superklasse

public class Angebot

{

// private Attribute

private int nummer;

private String name;

private double preis;

// Standardkonstruktor

public Angebot()

{

}

// Standard getter- und setter-Methoden

public void setNummer(int n){

nummer = n;

}

public int getNummer(){

return nummer;

}

//.....

// toString() Methode fasst alle Attribute als String zusammen und gibt diesen zurück

public String toString(){

return "Nummer: " + nummer + " Name: " + name + " Preis: " + preis;

}

}

// Produkt ist die ableitende Klasse von der Superklasse Angebot

public class Produkt extends Angebot

{

// Private Attribute die in der Klasse Produkt ergänzt werden

private String hersteller;

private double gewicht;

// Standardkonstruktor setzt den Standardwert auf 0

public Produkt (){

setNummer(0);// Diese Methode wurde von der Superklasse Angebot geerbt und kann hier benutzt werden

}

// Standard getter- und setter-Methoden

public void setHersteller(String h){

hersteller=h;

}

public void setGewicht(double g){

gewicht=g;

}

public String getHersteller(){

return hersteller;

}

public double getGewicht(){

return gewicht;

}

// Die Signatur dieser Methode ist identisch mit der Methode toString aus der Superklasse Angebot

// Daher überschreibt (Polymorphie) die Methode aus der Superklasse.

// Die ursprüngliche Methode aus der Klasse Angebot wird jedoch genutzt um diese zu erweitern

// Der Aufruf der ursprünglichen Methode erfolgt durch super.toString()

// An die Rückgabe werden die fehlenden Attribute angehängt

public String toString(){

return super.toString()+ " Hersteller: " + hersteller + " Gewicht: " + gewicht;

}

}