Ein wichtiger Bestandteil bei der objektorientierten Programmierung ist das Konzept der Vererbung. Hiermit ist es möglich Eigenschaften einer Klasse an seine Nachkommen weiter zugeben. Die Struktur, welche durch Vererbung entsteht, nennt man Vererbungshierarchie.
Vererbung
Java selbst ist komplett als Vererbungshierarchie aufgebaut. Alle in Java vorkommenden Klassen sind direkte bzw. indirekte Nachfahren der Klasse Object aus dem Paket java.lang. Eine solche Klasse wird Elternklasse, Superklasse, Basisklasse oder Oberklasse genannt. Die davon abgeleiteten Klassen nennt man Kindklasse, Subklasse oder Unterklasse. Der Vererbungsvorgang selbst ist eine gerichtete Beziehung zwischen der Eltern- und Kindklasse. Man spricht hierbei von Generalisierung.
Die Elternklasse ist eine Generalisierung der Kindklasse.
Die Kindklasse ist eine Spezialisierung der Elternklasse.
Man kann somit sagen, ein Objekt der Kindklasse ist ein Objekt der Elternklasse.
Dies gilt allerdings nicht in die Gegenrichtung. Ein Objekt der Elternklasse ist kein Objekt der Kindklasse. Der Grund hierfür liegt darin, dass eine Kindklasse eine speziellere Ausprägung der Elternklasse ist. Das heißt, dass diese alle Eigenschaften der Elternklasse besitzt und zusätzlich noch (speziellere) Eigenschaften. Somit erfüllt eine Kindklasse immer die Eigenschaften der Elternklasse, aber eine Elternklasse niemals die der (spezielleren) Kindklasse. Nach diesem ganzen Schwall an Terminologie schauen wir uns einmal so eine Vererbung an. Dazu bietet sich Verwendung der UML Notation an.
Bei der UML Notation der Vererbung werden beide Klassen mit einer gerichteten durchgehenden Linie verbunden. Der geschlossene, nicht ausgefüllte Pfeil zeigt immer auf die Elternklasse. Hieran kann man nun ablesen, dass die Klasse Kindklasse ein Nachfahre der Klasse Elternklasse ist.
In Java
Da wir uns nun schon etwas in der Begriffswelt der Vererbung und der zugehörigen UML Notation auskennen, schauen wir uns nun die Umsetzung in Java an. Für Vererbungsbeziehungen unter Klassen existiert das Schlüsselwort extends (deutsch: erweitert).
public class Kindklasse extends Elternklasse {}
Umgangssprachlich ausgedrückt erweitert also eine Kindklasse die Elternklasse.
Die Kindklasse erbt somit alle sichtbaren Eigenschaften der Elternklasse und kann zusätzlich noch weitere (speziellere) Eigenschaften implementieren. Dies testen wir jetzt einfach mal an einen Beispiel.
Dies soll einmal unsere Vererbungshierarchie darstellen. Es gibt eine Klasse Person, welche die Elternklasse repräsentiert. Zusätzlich gibt es noch die Klassen Programmierer und Manager, welche Kindklassen von Person sein sollen. Hieran kann man auch wieder die Beziehungen untereinander darstellen.
Ein Manager ist eine Person. Ein Programmierer ist eine Person.
Aber
Nicht jede Person ist ein Manager. Nicht jede Person ist ein Programmierer.
Wir wollen nun versuchen das obige UML Diagramm zu lesen. Wir haben also eine Klasse Person. Diese enthält ein Attribut name. Der Konstruktor dieser Klasse erwartet einen String Parameter aName, um den Namen der Person direkt bei der Erzeugung mit zu übergeben. Weiterhin gibt es eine Methode getName, welche uns den Namen der Person zurückliefern soll. Die Klasse Manager ist ein Kind der Klasse Person. Dies erkannt man an dem gerichteten Pfeil. Aus diesem Grund „erbt“ die Klasse Manager bereits das Attribut name sowie die Methode getName. Zusätzlich dazu implementiert sie noch ein Attribut namens gehalt mit der zugehörigen Methode getGehalt. Analog verhält sich dies ebenso bei der Klasse Programmierer, mit dem Unterschied, dass hier an Stelle von gehalt die lieblingsSprache als Attribut vorkommt. Beginnen wir nun mit der Implementierung der Klasse Person.
public class Person {
private String name = "";
public Person(String aName) {
this.name = aName;
}
public String getName() {
return this.name;
}
}
Dies kennen wir ja bereits alles. Eine normale Klasse, welche ein Attribut, einen Konstruktor und eine Methode enthält. Schauen wir uns nun die Klasse Manager an.
public class Manager extends Person {
private int gehalt;
public Manager(String aName, int aGehalt) {
super(aName);
this.gehalt = aGehalt;
}
public int getGehalt() {
return this.gehalt;
}
}
Diese Klasse enthält zusätzlich – zu dem bisher Bekannten – das Schlüsselwort extends gefolgt von der Klasse, von welcher sie erben soll. In diesem Fall also Person. Auch im Konstruktor von Manager gibt es etwas Neues zu sehen. Hier rufen wir über super den Konstruktor der Elternklasse auf und übergeben diesem den Parameter aName.
Mit dem Schlüsselwort
superwird immer die Elternklasse angesprochen.
Der Rest ist wieder bekannt. Die Klasse Programmierer sieht wieder so ähnlich aus.
public class Programmierer extends Person {
private String lieblingsSprache = "";
public Programmierer(String aName, String aSprache) {
super(aName);
this.lieblingsSprache = aSprache;
}
public String getLieblingsSprache() {
return this.lieblingsSprache;
}
}
Sie erbt von der Klasse Person und verwendet in ihrem eigenen Konstruktor den Konstruktor ihrer Elternklasse. Das Ganze testen wir nun innerhalb einer main Methode.
public static void main(String[] args) {
Person horst = new Person("Horst");
Programmierer sebastian = new Programmierer("Sebastian", "Java");
Manager wendelin = new Manager("Wendelin", 50000000);
System.out.println(horst.getName());
System.out.println(sebastian.getName() + " " + sebastian.getLieblingsSprache());
System.out.println(wendelin.getName() + " " + wendelin.getGehalt());
}
Hier erzeugen wir ein Objekt der Klasse Person mit dem Namen horst. Dem Konstruktor von Person geben wir auch gleich den Namen “Horst” mit. Danach erzeugen wir ein Objekt der Klasse Programmierer mit dem Namen sebastian. Der Konstruktor hierzu bekommt “Sebastian” und “Java” als Parameter übergeben. Als drittes und letztes Objekt folgt wendelin der Klasse Manager mit den Parametern “Wendelin” und “50000000″ für den zugehörigen Konstruktor. Zum Schluss lassen wir uns nun noch einige Werte der Objekte ausgeben. Mit horst.getName() erhalten wir Horst als Rückgabe, da getName eine Methode der Klasse Person ist. Wir erhalten aber auch über sebastian.getName() den entsprechenden Namen Sebastian. Dies geschieht deshalb, da die Klasse Programmierer, wovon sebastian ein Objekt ist, die Methode getName von der Klasse Person erbt. Gleiches gilt ebenso für unser Objekt wendelin der Klasse Manager. Als Ausgabe erhalten wir.
Horst
Sebastian Java
Wendelin 50000000
Auf der nächsten Seite erfahren Sie einige Details, um zu bestimmen zu welcher Klasse ein Objekt gehört und wie man es in ein anderes Objekt umwandeln kann.




Kommentar verfassen