So, in diesem Abschnitt geht es jetzt um die Aufrufreihenfolge.
Auch hier knüpfen wir an das dynamische Binden
an oder knüpfen wir an die Vorlesung 3 an.
Dort, wo wir das dynamische Binden besprochen haben.
Und wir müssen jetzt uns überlegen, wie hängt denn das miteinander zusammen?
Das, was wir eben gezeigt haben,
wir können in Oberklassen etwas zusammenfassen, führt dazu,
dass wir manchmal mehrere Methoden haben, die genauso heißen.
Und dann ist nicht klar, wo passiert was.
In diesem Beispiel ist es hier diese Methode, mache Jahresabschluss,
die es bei Konto gibt, weil das Superklasse bei der Oberklasse.
Und bei der Subklasse, bei der Unterklasse gibt es die auch.
Die Frage ist, wie rufen wir die denn auf?
Auf Fulja 18 kommt dazu eine Antwort. Wir suchen zunächst wieder
statischer Typ und dynamischer Typ. Ja, das hat mir
auch in Vorlesung 3. Bitte schauen Sie da nochmal nach.
Zunächst erstmal der statische Typ ist ja das, was ich zur Übersetzungszeit kenne.
Da wird zunächst erstmal das genommen, was am weitesten in der Spezialisierung,
in der Typ Hierarchie unten ist, wird gewählt.
Und da schauen wir danach passender Name und passender Parametertyp
Bitte nur der Aufrufparameter nach Rückgabetypen, wird da nicht geschaut.
Das macht der Compiler, er ordnet zu,
welche kann das sein, das Erfund des statischen Typs.
Aufgrund des dynamischen Typs, das ist ja das,
was wir zur Laufzeit erst wissen, erst erfahren,
was hat denn das Exemplar für einen Typ,
von welcher Klasse stammt das, das können wir erst zur Laufzeit suchen,
nämlich erst nach dem, bei dem dynamischen Binden.
Und da wird angefangen in der Klasse des aktuellen Objekts.
Dort wird gesucht und dann geht es nach oben.
Das schauen wir uns auf dem nächsten Beispiel mal an.
Das Beispiel ist ein bisschen abgefahren. Ich hoffe,
sie stören sich da nicht so sehr dran.
Ist ein bisschen konstruiert, damit wir das so klein haben,
damit wir die wesentlichen Effekte herausarbeiten können.
Wir haben zweimal so eine Farbungsbeziehung und zwar einerseits zwischen Personen und Diabetiker
und wir brauchen das Gleiche auch noch für die Parameter.
Da haben wir nochmal zwischen Nahrung und die ethische Nahrung.
Also diese Parameter, die sind hier auch,
gibt es in Allgemeineren und den spezielleren einfach nur,
damit wir
zwei unterschiedliche haben
Die Verarbung spielt aber vor allen Dingen hier eine Rolle.
Das ist das, wo wir die Implementationsvererbung auch haben.
Und zwar haben wir hier gleich zwei Fälle in unserem Beispiel.
Das eine ist, wir haben eine Methode,
eine Operation bei Personen mit Verzehre und Parametertyp Nahrung.
Das Gleiche haben wir hier aber auch.
Verzehre und Nahrung. Das heißt, in dem Zustand,
in dem Stand, wenn wir ein Exemplar von Diabetiker nehmen,
da würde dann diese Methode, die Relevante sein,
weil wir hier hier überschrieben haben.
Es wird also nicht geerbt, weil die von oben Hier
unten nochmal ist mit gleichen Namen, gleichen Parametertyp, es wird überschrieben.
Hier haben wir noch eine zusätzliche, das war überladen,
das ist bitter, müssen Sie jetzt auseinanderhalten,
weil wir hier einen anderen Parametertyp haben.
Das merkt der Compiler auch beim statischen Binden,
dass das zur Übersetzung seid, dass das ihr ein anderer Typ ist.
So, das ist erstmal während der Übersetzung würden wir
die Operation nehmen, die hier unten am besten passt von
diesen beiden
Zur Laufzeit, das würde zum Beispiel,
könnte das so aussehen, ja,
wir erzeugen ein Exemplar von der Klasse Diabetiker von dieser Klasse und dann rufen wir,
das wird dem Referenz,
der Referenzvariablen P zugewiesen und wir rufen Verzehre von P auf und geben mit dem Parameter diethischen diabetische Nahrung.
Und dann wäre das diese überladene Methode und diese würde nicht passen. Ja,
also hier, ach so, das war das,
er fehlt noch das Geringe von dem Übersetzungszeit unserer Laufzeit,
fangen wir hier unten an zu suchen,
wir finden das für die Nahrung, für die allgemeine Nahrung,
hier für die diabetische Nahrung hier.
Und wenn wir das hier schon finden, brauchen wir nicht nach oben gehen mehr.
Soweit zu diesem Beispiel. Auf dem folgenden Beispiel, auf der Folgenfolie,
sieht das erstmal auf den ersten Blick ganz ähnlich aus,
aber bitte achten Sie darauf, wir haben hier das getauscht.
Also hier ist bei Person, die Methode verzehre,
mit dem Typ diabetische Nahrung. Das ist die, die hier
unten wieder vorkommt. Also hier haben wir auch ein Überschreiben,
aber bitte jetzt anders als in der vorgehenden Methode,
haben wir diabetische Nahrung überschrieben, nämlich hier mit der Unterklasse.
Und das mit dem Verallgemeinerten haben wir nur hier das Überladene.
Das gibt es hier oben nicht. Und dann ist das so,
dass wir zur Übersetzungszeit natürlich wieder die Operation suchen,
wenn wir die mit diabetischer Nahrung brauchen,
dann würden wir die hier oben finden.
Ja, wenn wir hier, wir haben Verzehre,
diabetische Nahrung, die ist dann hier oben da.
Und wenn wir zur Laufzeit suchen, ja,
dann fangen wir hier an, weil Wir haben ein Objekt,
ein Exemplar der Klasse Diabetiker hier genommen.
Und dann nehmen wir die. Soweit dazu. Jetzt schauen wir uns nochmal,
also der Unterschied zur Vorgehen ist jetzt,
dass wir hier unten nur eine der beiden Operationen haben,
einmal hier oben die und dann hier unten die.
Bevor wir starten, erstmal gleich die Überlegung,
wenn wir ein Exemplar von Diabetiker erzeugen, was wir hier machen zur Laufzeit,
welche Operationen haben wir denn hier zur Verfügung?
Welche Methoden? Ja, wir haben auch hier oben
die von die diabetische Nahrung
hier unten
Auch da. Also wir unten hat ja eigentlich zwei, zur Laufzeit hat er hier zwei. Ja,
zur Übersetzungszeit wiederum die speziellste Operation an eine des statischen Typs finden für den Diabetiker,
ist die, auch wenn das hier mit die ideabetische Nahrung aufgerufen wird,
da das die Oberklasse erfüllt, das, die Untere darf das,
darf immer ersetzt werden durch die Oberklasse, das heißt,
die erfüllt das und wir würden diese hier nehmen können und zur Laufzeit würden wir in der Vererbungshierarchie suchen,
diabetische Nahrung gibt es hier und nicht, ja,
also wir fangen hier an zwar an zu suchen,
Im Exemplar, wir haben ja dieses Exemplar gebildet,
im Exemplar der Klasse,
dort gibt es das aber nicht,
dann gehen wir also nach oben und suchen hier.
Das war das, was hier ein paar Folien vorher stand,
da muss ich jetzt selber nachschauen,
ob wir das auf 18, ja genau hier,
wir suchen nach der passenden Implementierung entlang der Vererbungshierarchie.
Jetzt möchte ich wieder dahin zurückspringen, wo ich gerade war.
Nein, jetzt war ich versprungen, ja genau,
hier waren wir
Soweit, soweit dazu, zu der aufrufreien Folge. Es gibt die Möglichkeit,
dass wir nicht nur komplett eine Methode überschreiben,
indem wir die in der Unterklasse,
dass ich gehe nochmal eine Folie zurück,
zur 21,
ja,
hier haben wir die hier unten eine neue gemacht durch Überladen
und die ist geblieben,
noch was vorher
Na, weil man hier war so, dass wir die überschrieben haben.
Also die hier oben gleiche Signatur, gleiche Name und Parametertypen.
Und hier unten haben wir sie komplett überschrieben. Es gibt die Möglichkeit,
dass wir das noch etwas kombinieren durch eine Kombination machen.
Wir können die also mittels eines Schlüsselwortes, können wir sagen,
okay, nimm ein bisschen von oben und an Züge noch etwas dazu.
Das heißt, dass wir aus der eigentlich überschreibenden Methode
die überschriebene, die ursprüngliche aufrufen können.
Das können wir mit diesem Operator,
mit dem Schlüsselwort
super machen
Also super, Punkt, mache ich Jahresabschluss.
Damit verweisen wir auf das, was in der Oberklasse steht.
Und dann können wir noch was hinzufügen. Ja,
also wir überschreiben sie nicht komplett, sondern erweitern das.
Und damit haben wir eine Möglichkeit mehr, das zu kombinieren.
Hier noch ein Hinweis, man kann das nicht über mehrere Stufen machen,
das geht immer nur mit der direkten Oberklasse.
Also super, Punkt, super. Und dann mache ich
Jahresabschluss, das würde nicht funktionieren. Soweit dazu,
wenn wir die Operationen hier Wenn wir Redefinition haben,
dann ist die Situation so, dass wir überlegen, dass es,
wenn wir selbst aufrufen, hier selbst aufrufe zwischen den Dingern haben, würde das weitergegeben.
Das ist ein bisschen spezieller und das schauen wir uns hier zunächst allgemein an.
Und beim nächsten auf dem nächsten Bild dann mit Java.
Und zwar haben wir hier die Situation,
dass wir in der Oberklasse,
in der Superklasse zwei Operationen haben und die eine ruft
die andere auf
Das darf man immer machen, Surfaufrufe, this Aufrufe,
das darf man immer machen, die eine Methode darf ja die andere benutzen.
So, wenn wir jetzt eine Unterklasse haben,
dann wäre erstmal in der Unterklasse die gleiche Situation. Ja,
wenn wir Vererbung haben, ja, wird Operation 1,
wird geerbt, Operation 2 wird geerbt und dann wäre das
hier unten ganz genauso der Einruf, den anderen auf.
Wenn wir den Sonderfall haben, dass wir die Operation 2 hier unten redefinieren,
das heißt, hier haben wir die gleiche,
der gleichen Bezeichner, Gleiche Parameter, aber eine neue Implementierung,
dann würde das hier oben überschrieben.
Und dann haben wir hier unten,
wenn wir diese mit Operation 1 einen Aufruf auf Operation 2 haben,
dann, wir merken uns,
wir fangen ja beim Suchen zur Laufzeit immer im Exemplar in der aktuellen Klasse an,
dann würden wir das hier zuerst finden und würden nicht das nehmen.
Das passiert auch, auch wenn das eigentlich
eine geerbte Methode ist
Ja, wir gucken immer in dem eigenen Exemplar der eigenen Objekte. Die Metapher,
zu der wir gleich auch noch auf einer Folie haben,
wir denken uns das so, als wäre das immer auf einer,
als wäre das kopierter Code.
Ja, und damit wird,
obwohl wir das eigentlich eine geerbte Methode ist und die ruft etwas,
hier oben würde sie das aufrufen, aber da wir hier sind,
ruft sie in dem Exemplar das hier auf.
So, das Ganze steht nochmal an dem Beispiel,
wir haben wieder Konto und Sparbuch und jetzt haben wir hier
eine Operation
Druckejahresbericht, und die ruft auf Macherjahresabschluss. Das Schema ist genau das,
was wir eben im Bund gesehen haben, hier in Java,
also bei Mache Javas, bei Drucker in der Oberklasse,
haben wir einmal dieses Druckejahresbericht, und das ruft Mache Jahresabschluss auf.
Und ja, unten nahm er das Druckejahresbericht nicht.
Aber mache Jahresabschluss, haben wir redefiniert. Gleiche Situation,
ich springe mal eine Folie zurück, sah das hier ganz genauso aus.
Die eine haben wir nur hier oben,
hier unten haben wir sie nicht, sie wird also geerbt,
die untere haben wir zweimal, ist hier unten redefiniert.
Ja, also hier Togi-Jahresbericht gibt es hier und nicht,
wird also geerbt. Mache Jahresabschluss haben wir oben und unten.
Hier steht es nochmal, Public Void, Jahresabschluss ohne Parameter.
Hier, Public Void, Jahresabschluss. Mache ich Jahresabschluss.
Ist hier nicht da. Hier unten haben wir sie,
oder vielleicht ist es hier auch nochmal da.
Hier unten haben wir sie überschrieben. Und da rufen wir
dann von dem eigenen das auf. So. Zu allem
Überfluss ist jetzt ja auch noch der Super mit drin,
das können wir getrost ignorieren.
Das ist das gleiche Schema wie vorher. Mit Super wird
man doch nochmal was anderes aufrufen. Aber das tut erstmal
Nicht zur Sache, nur dass wir die Kombination haben.
Hier ist es wichtig, wir haben hier ein Beispiel für diese Konstellation.
Hier unten wird etwas überschrieben. Damit haben wir die Frage beantwortet.
Ich gehe noch mal zurück zu der Frage von Folie 3.
Die haben wir, diese Frage, wie wird beim dynamischen Binden gesucht?
Das stand, die Antwort stand auf Folie 18.
Dynamische Spinden war das hier unten. Hier oben war das
mit dem statischen Typ, hier unten beim dynamischen Binden.
Da wird gestartet in der Klasse des aktuellen Objekts,
des Exemplars
Und gehen, wenn wir da nichts finden,
eins nach oben, eins nach oben, eins nach oben.
Soweit dazu. Wir kommen später zum nächsten Punkt.
Nochmal auf Vererbung und Abstraktion
weiterhin zurück