860 likes | 1.07k Views
Vererbung. Das Prinzip der Vererbung im täglichen Leben:. Walter besitzt ein Haus. Walter erbt nun 10000Euro. Also besitzt er insgesamt:. +. 10000. Erblasser. Erbe. In Java:. --->. In Java darf man einen Erben (abgeleitete Klasse) selbst basteln. abgeleitete Klasse. Basisklasse.
E N D
Walter erbt nun 10000Euro. Also besitzt er insgesamt: + 10000
Erblasser Erbe In Java: ---> In Java darf man einen Erben (abgeleitete Klasse) selbst basteln abgeleitete Klasse Basisklasse --->
Statt abgeleiteter Klasse sagt man auch:Unterklasse, Sohnklasse, Subklasse
Eine abgeleiteteKlasse wird in Java wie folgt angegeben: class Ei extends Huhn{ ... } Bezeichner Basisklasse abgeleitete Klasse
Die abgeleitete Klasse (kurz: Ableitung) besitzt automatisch alle Member (Ausnahme: Konstruktor) der Basisklasse.
Von einem Flachdachhaus wird ein Modell (Draufsicht) erstellt:
Der Einfachheit halber wird nur die Grundfläche (ohne Zimmer, usw.) des Hauses abgebildet.Aufgabe:Realisieren Sie die Klasse Modell in Java.
class Modell{ private double l; private double b; public Modell(double pl, double pb){ l = pl; b = pb; } public void setL(double pl){ l = pl; } // weiter...
public void setB(double pb){ b = pb; } public double getL(){ return(l); } public double getB(){ return(b); } public double getFlaeche(){ return(l*b); } };
Jetzt soll ein “genaueres“ Modell des Flachdachhauses erstellt werden: Modell aus Styropor (oder Ton). Aufgabe:Realisieren Sie in Java die Klasse Gmodell.
Standardmäßig könnte man das mit den 3 Attributen Länge, Breite, Höhe und den zugehörigen set- und get-Methoden machen. Also wie folgt:
class Gmodell{ private double l; private double b; private double h; public Gmodell(double pl, double pb, double ph){ l = pl; b = pb; h = ph; }
public void setL(double pl){ l = pl; } public void setB(double pb){ b = pb; } public double getL(){ return(l); } public double getB(){ return(b); }
public void setH(double ph){ h = ph; } public double getH(){ return(h); } public double getVolumen(){ return(l*b*h); } };
Gibt es eine andere Lösung, bei der man sich Schreibarbeit sparen kann? Wie kann man Softwareteile dabei wiederverwenden ? Indem man die Vererbung benutzt.
Welche Member der Klasse Modell kann man übernehmen (erben) ?Welche Member kommen neu dazu ?
class Modell{ private double l; private double b; public Modell(double pl, double pb){... public void setL(double pl){... public void setB(double pb){... public double getL(){... public double getB(){... public double getFlaeche(){... }; Alle außer dem Konstruktor Welche Member müssen neu dazu ? Welche Member werden vererbt ?
extends Modell{ class Gmodell private double l; private double b; public: public void setL(double pl){... public void setB(double pb){... public double getL(){... public double getB(){... public double getFlaeche(){... } Die reliefförmig dargestellten Member werden geerbt. private double h; Die rot dargestellten Member kommen neu dazu. Wie wird eine Vererbung erreicht ? public Gmodell(double pl, double pb,double ph){... public void setH(double ph){... public double getH(){... public double getVolumen(){...
Aufgabe: Schreiben Sie das komplette Programm mit den zugehörigen Klassen in Java
public class MainVererbung1{ public static void main(String[] args){ // Anweisungen siehe später } } class Modell{ private double l; private double b; public Modell(double pl, double pb){ l = pl; b = pb; }
public void setL(double pl){ l = pl; } public void setB(double pb){ b = pb; } public double getL(){ return(l); } public double getB(){ return(b); } public double getFlaeche(){ return(l*b); } };
class Gmodell extends Modell{ private double h; public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } public void setH(double ph){ h = ph; } public double getH(){ return(h); } public double getVolumen(){ return(getFlaeche()*h); } } Diese Methode gibt es nicht in der Klasse Gmodell. Warum kann sie trotzdem verwendet werden? Weil ... 1) Die Methode von der Klasse Modell vererbt wird und es sie deshalb in Gmodell gibt 2) Weil die Methode public ist, kann auf sie zugegriffen werden. Mit super wird ein Konstruktor der Oberklasse aufgerufen. Näheres dazu später.
class Gmodell extends Modell{ private double h; public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } public void setH(double ph){ h = ph; } public double getH(){ return(h); } public double getVolumen(){ return(getFlaeche()*h); } } Wie heißt der Konstruktor der Oberklasse und wie viele Parameter hat er? Der Konstruktor heißt Modell und er hat zwei Parameter
class Gmodell extends Modell{ private double h; public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } public void setH(double ph){ h = ph; } public double getH(){ return(h); } public double getVolumen(){ return(getFlaeche()*h); } } Was könnte man statt dem Aufruf der Methode setH(ph) auch noch machen? h = ph;
class Gmodell extends Modell{ private double h; public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } public void setH(double ph){ h = ph; } public double getH(){ return(h); } double getVolumen(){ return(b*l*h); } } Warum ist diese Lösung falsch ? Die Member b und l gibt es zwar in der Klasse GModell (sie wurden vererbt). Allerdings sind sie private. Auf vererbte private-Member kann weder innerhalb noch außerhalb der Klasse zugegriffen werden.
class Gmodell extends Modell{ private double h; public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } public void setH(double ph){ h = ph; } public double getH(){ return(h); } double getVolumen(){ return(b*l*h); } } Die Methoden getB() und getL() sind public. Deswegen dürfen sie benutzt werden. Welche Lösung wäre auch noch möglich? return(getB()*getL()*h);
class Gmodell extends Modell{ private double h; public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } public void setH(double ph){ h = ph; } public double getH(){ return(h); } double getVolumen(){ return(b*l*h); } } h wird nicht vererbt und ist ein Attribut von Gmodell. Deshalb kann man innerhalb der Klasse Gmodell auf h zugreifen. Warum muss man getB() und getL() verwenden, aber nicht getH(), sondern h ? return(getB()*getL()*h);
class Gmodell extends Modell{ private double h; public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } public void setH(double ph){ h = ph; } public double getH(){ return(h); } double getVolumen(){ return(pb*pl*h); } } Warum ist das nicht korrekt? Auf die Variablen pb und pl kann nicht zugegriffen werden, da sie weder ... ein Attribut der Klasse, noch ein Parameter bzw. eine lokale Variable der Methode getVolumen() sind.
public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } Da die Klasse Gmodell von der Klasse Modell erbt, muss beim Anlegen eines Objekts der Klasse Gmodell auch der Konstruktor der Klasse Modell aufgerufen werden. Wird dies nicht gemacht, dann wird automatisch (ohne Zutun des Programmierers) der Standardkonstruktor der Klasse Modell aufgerufen. Was passiert, wenn der Standardkonstruktor nicht existiert ? Dann wird dieser automatisch vom Compiler angelegt, außer .... es gibt einen Konstruktor mit (1, 2, 3, ...) Parametern. Dann liefert der Compiler eine Fehlermeldung.
MerkeWenn ein Konstruktor der Unterklasse nicht mittels super(...) einen Konstruktor der Oberklasse aufruft, dann wird automatisch der Standardkonstruktor (=Konstruktor mit 0 Parametern) der Oberklasse aufgerufen. Der Sinn davon ist, dass alle Attribute (auch die der Oberklassen) einen definierten Wert bekommen sollen, auch wenn der Programmierer vergisst, den Konstruktor der Oberklasse aufzurufen.
Falls dieser Standardkonstruktor nicht existiert, wird er automatisch vom Compiler erzeugt, außer ein anderer Konstruktor (mit mindestens einem Parameter) existiert schon. In diesem Fall bringt der Compiler dann eine Fehlermeldung.Wenn man super(...) in einem Konstruktor benutzt, muss dies die erste Anweisung in dem Konstruktor sein, d.h. vor super(...) darf keine Anweisung stehen!
public Gmodell(double pl, double pb, double ph){ super(pl,pb); setH(ph); } Was würde also geschehen, wenn man diese Anweisung in unserem Programm weglassen würde? Dann würde automatisch der Standardkonstruktor der Klasse Modell aufgerufen werden. Da dieser nicht existiert und er auch nicht automatisch erzeugt wird (da es ja schon in der Klasse Modell einen Konstruktor mit zwei Parametern gibt) meldet der Kompiler einen Fehler.
Beispiel für die Benutzung der o.g. Klassen in einem Hauptprogramm.Welche Werte bekommen die Variablen in den Zuweisungen?
public class MainVererbung1{ public static void main(String[] args){ Modell m = new Modell(10,20); Gmodell g = new Gmodell(2,3,4); double a,b,c,f,v; // ... } } Bevor wir näher auf die einzelnen Anweisungen eingehen, noch eine Frage:Was ist streng genommen falsch bei dem Aufruf mit den obigen Parametern Die Parameter müssen eigentlich alle vom Datentyo double sein und nicht von Datentyp int. Doch der Compiler ist hier gutmütig, verzeiht und wandelt int in double um. Stichwort: "Parameterübergabe und Konvertierung" am Schluss dieser Präsentation.
public class MainVererbung1{ public static void main(String[] args){ Modell m = new Modell(10,20); Gmodell g = new Gmodell(2,3,4); double a,b,c,f,v; // ... } } Was ist m ?Was geschieht im Arbeitsspeicher? m Im Arbeitsspeicher wird "irgendwo" Speicher für ein Objekt reserviert, auf das m zeigt. Dieses Objekt besteht aus 2 "Schubladen" l und b und wird durch den zweiparametrigen Konstruktor Modell vorbelegt
public class MainVererbung1{ public static void main(String[] args){ Modell m = new Modell(10,20); Gmodell g = new Gmodell(2,3,4); double a,b,c,f,v; // ... } } Was ist g ?Was geschieht im Arbeitsspeicher? m Im Arbeitsspeicher wird "irgendwo" Speicher für ein Objekt reserviert, auf das g zeigt. Dieses Objekt besteht aus 3 "Schubladen" l, b h und wird durch den dreiparametrigen Konstruktor Gmodell vorbelegt. g
public class MainVererbung1{ public static void main(String[] args){ Modell m = new Modell(10,20); Gmodell g = new Gmodell(2,3,4); double a,b,c,f,v; // ... } } Gibt es einen Zusammenhang zwischen m und g ? m nein! g
Die Methode gibt es nicht in der Klasse Modell public class MainVererbung1{ public static void main(String[] args){ Modell m = new Modell(10,20); Gmodell g = new Gmodell(2,3,4); double a,b,c,f,v; a = m.getL(); b = m.getB(); c = m.getH(); f = m.getFlaeche(); v = m.getVolumen(); a = g.getL(); b = g.getB(); c = g.getH(); f = g.getFlaeche(); v = g.getVolumen(); } } Die Methode gibt es nicht in der Klasse Modell Was bewirken die folgenden Anweisungen? // a=10 // b=20 // Fehler !! // f=200 // Fehler !! // a=2 // b=3 // c=4 // f=6 // v=24
class Gmodell extends Modell{ private double h; public Gmodell(double pl, double pb, double ph){... public void setH(double ph){... public double getH(){... public double getVolumen(){... public double getFlaeche(){... } Alles gleich wie vorher außer, daß eine Methode gleichenNamens wie in der Basisklasse existiert, die die Oberfläche des Modells (Quaders) berechnet. Wie muss sie implementiert werden ?
double getFlaeche(){ return(2*(getL()*getB()+getL()*h +getB()*h)); } Warum ist diese Lösung falsch ? Die Member b und l gibt es zwar in der Klasse GModell (sie wurden vererbt). Allerdings sind sie private. Auf vererbte private-Member kann weder innerhalb noch außerhalb der Klasse zugegriffen werden. double getFlaeche(){ return(2*(l*b+l*h+b*h)); }
Es wird auf die Methode der Unterklasse und nicht der Oberklasse zugegriffen, weil die Methode der Oberklasse durch die Methode der Unterklasse verdeckt wird. public class MainVererbung1{ public static void main(String[] args){ double f; Gmodell g = new Gmodell(2,3,4); f = g.getFlaeche(); } // f=52 // 52=2(2*3+2*4+3*4) Von welcher Klasse (Modell oder Gmodell) wird diese Methode aufgerufen ?
Merke:Wenn die Methode in mehreren Klassen einer Vererbungshierarchie vorkommt, wird - relativ zu dem aktuellen Objekt aus gesehen - auf die in der Vererbungshierarchie am weitesten unten stehende Methode zugegriffen. Also: public class MainVererbung1{ public static void main(String[] args){ double f; Gmodell g = new Gmodell(2,3,4); f = g.getFlaeche(); } Wenn die Methode in der Unterklasse und in der Oberklasse vorkommt und auf ein Objekt der Unterklasse zugegriffen wird, wird auf die Methode der ... Unterklasse zugegriffen Wenn die Methode in der Unterklasse, aber nicht in der Oberklasse vorkommt und auf ein Objekt der Unterklasse zugegriffen wird, wird auf die Methode der ... // f=52 Unterklasse zugegriffen // 52=2(2*3+2*4+3*4) Wenn die Methode nicht in der Unterklasse, aber in der Oberklasse vorkommt und auf ein Objekt der Unterklasse zugegriffen wird, wird auf die Methode der ... Oberklasse zugegriffen
double getFlaeche(){ return(2*(h*getB()+h*getL()+ getL()*getB())); } getFlaeche könnte man auch anders implementieren ... double getFlaeche(){ double temp; temp= h*getL() + h*getB(); temp=2*(super.getFlaeche()+temp); return(temp); } Mit super ruft man die verdeckte Methode der Oberklasse auf, wobei super nicht die erste Anweisung in der Methode sein muss.