Eine Vererbung ist eine Beziehung zwischen Klassen. Die Beziehung lautet: Diese Klasse ist vom Typ der anderen Klasse. Sie bedeutet eine ODER-Relation bei einer Zusammensetzung.
Eine Beziehung zwischen Klassen wird mit extends festgelegt.
Beispiel: die Abgeleitete Klasse erweitert die Basisklasse:
public class A extends B
B asisklasse
A bgeleitete Klasse von der B asisklasse.
Alles was der Erbe nicht nennt, wird vom Beerbenden übernommen:
Methoden die geerbt werden, braucht man daher nicht neu zu nennen.
class Vater
String familienName;
string vorName;
Vater(String parameter){
familienName = parameter;
}
public void setVorname(String parameter){
vorname = parameter;
}
public String getFamilienName(){
return familienName;
}
public String getVorName(){
return VorName;
}
}
class Sohn extends Vater{
}
public class Start{
public static void main(String[] args){
Sohn roland = new Sohn("Geyer");
roland.setVorName("Roland");
System.out.println(roland.getVorName);
}
}
|
Jede Klasse muß einen eigenen Konstruktor enthalten. Wird kein Konstruktor im Erbe angegeben, wird der Konstruktor des Erben genommen, der keine Parameter enthält. Achtung: Wurde in der zu erbenden Klasse mindestens ein Konstruktor definiert, wird KEIN Standardkonstruktor in dieser Klasse erzeugt! Daher kann auch keiner weitervererbt werden!
Obwohl nicht angegeben, leitet sich jede Klasse in Java von der Klasse Object ab. API: java.lang.Object
Der Aufruf geerbter Konstruktoren oder Methoden erfolgt durch super.
Wird der geerbte Konstruktor aufgerufen, muss diese Anweisung in der ersten
Zeile des Konstruktors stehen.
Beispiel:
MyKlass(parameter,neuerParameter){
super(parameter);
neu = neuerParameter;
}
Genauso erfolgt der geerbte Methodenaufruf:
Beispiel:
public int doppeltGehalt(){
gehalt = super.einfachGehalt();
doppeltGehalt = 2*gehalt;
return doppeltGehalt;
}
import Fahrzeug
class Mercedes extends Fahrzeug{
/////////////////Implementierung/////////////////////////////////
//Instanzvariablen
privat String farbe;
privat int liter;
privat int geschwindigkeit;
//Konstruktor
Mercedes(String parameter1, int parameter2){
super ( parameter1,parameter2); //####farbe + liter GEERBT
int geschwindigkeit = 0;
}
//Methoden der Klasse Fahrzeug
private void beschleunigen(int gibGas){
geschwindigkeit = super(geschwindigkeit) + 50;
}
///////////////////Schnittstelle////////////////////////////////
//setter Methoden
public void setMyGeschwindigkeit(int pMyGeschwindigkeit){
geschwindigeit = pMyGeschwindigkeit;
}
//getter Methoden
public String getFarbe(){
super.getFarbe();//#################GEERBT
}
public int getMyliter(){
return liter;
}
public int getMyGeschwindigkeit(){
return geschwindigkeit;
}
}
|
Super-Klassen können ihre Fähigkeiten an ihre sub-Klassen weitergeben.
Da sub-Klassen diese Fähigkeiten nicht nur erben, sondern auch weiterentwickeln
können, spricht man auch von Generalisierung und/oder Spezialisierung,
je nach Sichtweise in der Vererbungslinie.
Entscheidend ist, welches Attribut generalisiert wird. Es soll nur eine Eigenschaft
pro Hierachie generalisiert werden. Eine entstehende Unterklasse ist ein Spezialfall
der Oberklasse. Eine Klasse soll ihre Art, nicht aber ihre Rolle spezialisieren.
Eine neue Rolle soll besser durch Komposition entstehen!!

Basisklassen sollen unveränderbar sein, denn erben bedeutet auch, dass
der Typ geerbt wird!!! Wichtig wäre, dass die Klassen einer Hierachie daher
die Schnittstelle nicht ändern. Werden Änderungen der Schnittstelle
in der spezialisierten Klasse durchgeführt, muss nach der Typenumwandlung
in die Klasse, die dies zur Verfügung stellt, der geänderte Typ genannt
werden! Ist der Wert ein elementarer Datentyp ist damit die Sache erledigt.
Zwischen Objekten funktioniert das nur innerhalb der Vererbungshierachie. Da
die Subklasse mit einem Datentyp der Superklasse, die angeblich erweitert wurde
nichts anfangen kann, können nur Typen der generalisierten Klasse auf Typen
der spezialisierenden Klasse, die ja den generalisierten Typ enthält umgewandelt
werden (im weiteren Sinne: auf den Typ der Spezialklasse verallgemeinern). Dies
geschieht durch Nennung der Klasse, eingeschlossen zwischen zwei runden Klammern,
vor Aufruf des Objektes.
Beispiel zum Diagramm:
Einen Unbeschäftigten anlegen:
Unbeschäftigt person1 = new Unbeschäftigt();
person1.setName = "roland";
// jetzt umwandeln:
Jetzt benötige ich den Typ Person: (Person) person1.getName();
weitere Beispiele siehe API: java.awt, API: javax.swing
Ein Vorteil der Vererbung liegt in der Wiederverwendung bestehender Ressourcen
Die Unterklasse kann den privaten Teil der Oberklasse sich antypisieren, nicht
jedoch auf die Werte dieser Attribute zugreifen!!
Änderungen an der Wurzel einer Vererbungshierachie beeinflussen alle erbenden
Klassen dieser Hierachie!
Im schlimmsten Fall bewirkt eine Methode ganz was anderes. Damit müssen ALLE erbenden Klassen entsprechend verändert werden!!! = Hauptnachteil der Vererbung! Das System kann unüberschaubar mit zuvielen Abhängigkeiten versehen werden.
Um das einzuschränken kann man nur die Methodennamen und die Signatur der Methode = Schnittstelle der Klasse ohne Implementierung festlegen. Das bedeutet, dass diese Klasse nur abstrakte Methoden zur Verfügung stellt. Auf diese Weise kann man eine gemeinsame Schnittstelle der gesamten Klassenhierachie festlegen unabhängig von der tatsächlich implementierten Methode.
Eine abstrakte Methode wird durch abstract definiert, ist immer public und beinhaltet keinen Methodenrumpf:
public abstract void eineOperation();
Wenn Merkmale zu organisieren sind, die in der Klassenerbfolge zwingend implementiert
werden müssen, können sie als abstrakte Klasse definiert werden.
Abstrakte Operationen können nur in abstrakten Klassen definiert werden.
Abstrakte Klassen können auch nicht abstrakte Teile enthalten!
Durch final vor Namensnennung einer Deklaration (Variable, Methode, Konstruktor,
Klasse) kann eineVererbung und die damit verbundenen Möglichkeit einer
Überschreibung (Sicherheit!!) bzw. dynamischen Bindung verhindert werden.
In einer finalen Klasse ist natürlich alles bereits final! Da bei final
die gesamte Vererbungskette nicht durchsucht werden muss, wird die Durchführung
des Codes beschleunigt.
Durch einen private Konstruktor kann ein Vererbungsversuch unterbunden werden!
Static legt fest, das es nur ein einmaliges Vorkommen gibt!
Die Nachteile einer Vererbung können durch die Verwendung einer Hüllenklasse statt der Vererbung aufgehoben werden:
interface Vater
public void setVorname(String parameter){}
public String getFamilienName(){}
public String getVorName(){}
}
class Sohn implements Vater{
private final Vater vomVater;
String familienName;
string vorName;
public Sohn(Vater instanz){
vomVater = instanz;
}
public void setVorname(String parameter){
vomVater.setVorname(String parameter);
vorname = parameter;
}
public String getFamilienName(){
vomVater.getFamilienName();
return familienName;
}
public String getVorName(){
vomVater.getVorName();
return VorName;
}
}
|