Aber du rufst in Zeile 22 doch nur wieder die Methode der Superklasse auf (dafür dient das Schlüsselwort super)!
[JAVA=22]return super.toString();[/code]
Da musst du dann natürlich was anderes hinschreiben, versuch halt mal testweise sowas:
Du rufst zwar mit super.toString() eine Methode der Basisklasse auf, aber dort wird ja this.getClass() aufgerufen und damit landest du in der getClass()-Methode der abgeleiteten Klasse. Probier doch mal statt super.toString() super.getClass().toString() aus.
Das wäre etwas anderes als das was ich brauche. Das muss bzw. sollte schon so wie beschrieben ablaufen. Mein (Verständnis-)Problem dabei ist, dass trotz "this" die abgeleitete Methode aufgerufen wird.
Hinweis: das Beispiel ist etwas vereinfacht. Die abgeleitete Methode macht - nachdem die Basis-Methode ihren Job erledigt hat - noch etwas. Daher ist es wichtig, dass in der Basisklasse die Basis-Methode ausgeführt wird.
Das this kannst du dir an der Stelle sparen, das bewirkt gar nichts. getClass() wird von der abgeleiteten Klasse überschrieben und durch die Polymorphie wird automatisch die Methode in der abgeleiteten Klasse aufgerufen. Verwende Test.class.toString().
Es wird immer die Methode in der abgeleiteten Klasse ausgeführt - das willst du ja auch, sonst hättest du die nicht überschrieben ;-)
Wenn du trotzdem den Code der Vaterklasse aufrufen willst geht das nur mit
Java:
super.funktionC();
Schau dir das folgende Beispiel an:
Der erste Teil der Ausgabe ist völlig klar - funktionA -> funktionB -> funktionC alle in der Superklasse
Der zweite Teil mag dich vielleicht überraschen
Die funktionA in der Subklasse ruft funktionB auf welche hier nicht implementiert ist - also wird der in der Superklasse implementierte code ausgeführt
Diese ruft die funktionC auf und, das es sich um ein Objekt der Subklasse handelt wird der Code in der Subklasse ausgeführt.
Zuerst die Ausgabe:
Code:
Aufruf funktionA direkt in der Superklasse
Superklasse.funktionA()
Superklasse.funktionB()
Superklasse.funktionC()
Aufruf funktionA in der Subklasse
Subklasse.funktionA()
Superklasse.funktionB()
Subklasse.funktionC()
publicclassTest{publicstaticvoidmain(String[] args){Superklasse superKl =newSuperklasse();Subklasse subKl =newSubklasse();System.out.println("Aufruf funktionA direkt in der Superklasse");
superKl.funktionA();System.out.println();System.out.println("Aufruf funktionA in der Subklasse");
subKl.funktionA();}}
Also du willst aus funktionB die funktionC in der Superklasse aufrufen?
Warum hast du die denn überschrieben?
Instanziere ein Objekt vom Typ Superklasse und dann geht es so wie du willst
Im Objekt vom Typ Subklasse ist die Methode überschrieben, das heisst schlicht und ergreifend nicht mehr sichtbar.
Wenn du das machen müsstest, hättest du die Methode der Vaterklasse nicht überschreiben sollen.
Also entweder die Richtig Klasse instanzieren oder der Methode in der Subklasse einen anderen Namen geben.
Ganz einfach: die Basis-Klasse soll die in ihr deklarierte Methode benutzen und nicht die durch irgendeine abgeleitete bzw. überschriebene. Zumindest hätte ich das gerne. Anscheinend geht das aber nicht.
Der Hintergrund ist der folgende: eine abstrakte Basis-Klasse garantiert eine Eigenschaft. Diese Eigenschaft wird mittels des Konstruktors initialisiert, der die entsprechende set-Methode aufruft. In einer abgeleiteten Klasse wird die set-Methode überschrieben. Diese Methode (der abgeleiteten Klasse) ruft die überschriebene Methode (der Basis-Klasse) auf und macht dann noch etwas. Für dieses etwas wird eine Eigenschaft der abgeleiteten Klasse benutzt, die im Konstruktor initialisiert wird. Nur: wenn die Basis-Klasse die Methode (der abgeleiteten Klasse) aufruft, ist die Eigenschaft der abgeleiteten Klasse natürlich noch nicht initialisiert.
Nur: wenn die Basis-Klasse die Methode (der abgeleiteten Klasse) aufruft, ist die Eigenschaft der abgeleiteten Klasse natürlich noch nicht initialisiert.
Die Basis-Klasse kann niemals die Methode einer abgeleiteten Klasse direkt aufrufen denke ich. Du kannst in der Sub-Klasse die überschriebene Methode um super.method() erweitern, dann wird die Methode der Basis-Klasse aufgerufen. Ansonsten wird die Methode der Basis-Klasse nur dann aufgerufen, wenn es wirklich ein Objekt vom Typ Basis-Klasse gibt. Wie denn auch sonst?
Sorry aber zu welchem Zeitpunkt ruft denn da die Basis-Klasse die Sub-Klasse auf? Es ist doch vielmehr so, dass die Sub-Klasse eine Methode der Basis-Klasse aufruft. Das getClass() bezieht sich dabei auf die Sub-Klasse, weil die Methode ja auch von dieser ausgeführt wird und nicht von der Basis-Klasse.
Rufst du die Methode der Basis-Klasse direkt aus von einem Objekt der Basis-Klasse auf, dann wird dir getClass() natürlich auch das liefern, was du erwartest.
Java:
publicclassBasicClass{publicvoidmethod(){System.out.println(getClass());}publicstaticvoidmain(String[] args){BasicClass basic =newBasicClass();SubClass sub =newSubClass();
basic.method();
sub.method();}}classSubClassextendsBasicClass{@Overridepublicvoidmethod(){super.method();}}
Edit: Das Beispiel soll eigentlich nur nochmal verdeutlichen, dass zuerst eine Variable vom Typ BasicClass die Methode aufruft, danach eine Variable vom Typ SubClass. Und die Methodenaufrufe beziehen sich eben immer auf das Objekt, das es ausführt, deswegen kommt auch beim zweiten Mal SubClass und nicht BasicClass heraus. Das ist vielleicht dein Denkfehler, dass du dich da zu sehr an den "Ort" der Methode klammerst.
Er hat ein Objekt vom Typ Subklasse
Er will aus der funktionB() (die es nur in der Superklasse gibt) die funktionC() aufrufen, will aber dass der Code Superklasse.funktionC() ausgeführt wird obwohl die funktionC() überschrieben ist.
Ich sag es jetzt halt mal direkt - wer das machen will hat entweder einen groben Architekturfehler begangen oder keine Ahnung von Vererbung!
Eine andere Art der Erklärung - du hast ein Objekt vom Typ Subklasse.
Da drin sind funktionA() und funktionC() implementiert - die funktionB() wird sozusagen in dieses Objekt kopiert - es gibt in diesem Objekt den Code den du ausführen willst gar nicht.
(Ich weiss, dass es so nicht wirklich stimmt, aber es verhält sich so wie wenn ... )
Musst du hier die Methode setName(String) im Konstruktor aufrufen? Denn da ist ja der (Denk-)Fehler begraben. Ich weiß nicht was du in deinem konkreten Beispiel noch so alles tun musst (außer den Namen zu übergeben), aber wenns wirklich nur das ist, kannst du dir den Aufruf auch sparen und da "nur" eine Zuweisung machen. Ansonsten gibts noch einige Alternativen, um das Problem zumindest hier zu lösen, aber da ich die genauen Anforderungen nicht kenne, ists natürlich schwer zu beurteilen.
Musst du hier die Methode setName(String) im Konstruktor aufrufen? Denn da ist ja der (Denk-)Fehler begraben.Ich weiß nicht was du in deinem konkreten Beispiel noch so alles tun musst (außer den Namen zu übergeben), aber wenns wirklich nur das ist, kannst du dir den Aufruf auch sparen und da "nur" eine Zuweisung machen.
Die (Original-)Klasse garantiert, das die Eigenschaft (im konkreten Beispiel hier: name) immer erfüllt ist. Das wird dadurch verwirklicht, dass die Eigenschaft "privat" ist und nur mittels der set-Methode geändert werden kann. Eine einfache Zuweisung kommt daher nicht in Betracht. Weiterhin muss die Eigenschaft durch den Konstruktor initialisiert werden.
Was ich noch nicht verstanden habe: worin besteht der Denkfehler?
Ansonsten gibts noch einige Alternativen, um das Problem zumindest hier zu lösen, aber da ich die genauen Anforderungen nicht kenne, ists natürlich schwer zu beurteilen.
Wenn du willst, dass man sie nicht überschreiben kann: Mach ein "final" davor.
Wenn das nicht geht, weil die Methode manchmal doch überschrieben sein soll, musst du nochmal überlegen: bei der gleichen Methode kann nicht manchmal die Methode der Unterklasse und manchmal die Methode der Basisklasse rauskommen.
Das sollte dann wohl eher 2 Methoden sein, denk ich mal.
Die (Original-)Klasse garantiert, das die Eigenschaft (im konkreten Beispiel hier: name) immer erfüllt ist. Das wird dadurch verwirklicht, dass die Eigenschaft "privat" ist und nur mittels der set-Methode geändert werden kann. Eine einfache Zuweisung kommt daher nicht in Betracht. Weiterhin muss die Eigenschaft durch den Konstruktor initialisiert werden.
Also ich hab das jetzt nicht verstanden. Was ist eine erfüllte Eigenschaft? Private Variablen können noch immer in der Klasse und deswegen auch insbesondere im Konstruktor zugewiesen werden, in der sie stehen. Daran ändert auch ein vorhandener Setter nichts.
Der Denkfehler und das eigentliche Problem liegen IMO darin, dass du meine Erklärungen nicht verstanden oder wohl eher (Sorry wenn ich direkt bin) gar nicht wirklich gelesen hast.
Wer Code überschreibt will ganz bewusst, dass der überschriebene Code eben NICHT mehr ausgeführt wird - Punkt!
Es gibt eine Möglichkeit das doch zu tun und das ist es aus der abgeleiteten Klasse das mit
Code:
super.funktionB()
zu machen. Punkt.
Denk zur Laufzeit in Objekten und NICHT in Klassen! Wenn du ein Objekt der abgeleiteten Klasse hast gibt es kein "aus der Superklasse" ---- es gibt keine Superklasse, es gibt nur ein Objekt der Subklasse - Punkt.
Wenn sogar ich es begriffen habe, kann es nicht soooo schwieirig sein :bahnhof:
Ich löse ein ähnliches Problem meistens mit einer speziellen init-Methode, die von der Unterklasse aufgerufen werden muss. Das ist zwar nicht 100% sicher, aber für die meisten Fälle gut genug.
Ich denke das ist der springende Punkt. Ein Objekt vom Typ Subklasse kann eben per Definition nicht eine Methode der Basisklasse aufrufen, wenn diese überschrieben wurde. Wenn du die Methode aus der Basisklasse verwenden willst, darfst du sie nicht überschreiben und musst die Methode in der Subklasse anders benennen. Nur wenn du das tust, dann geht dir eben der Vorteil der Vererbung verloren und du kannst die Methode wirklich nur dann aufrufen, wenn du weißt, dass dein Objekt vom Typ Subklasse ist.
Private Variablen können noch immer in der Klasse und deswegen auch insbesondere im Konstruktor zugewiesen werden, in der sie stehen. Daran ändert auch ein vorhandener Setter nichts.
Das ist richtig. Die Einhaltung der Zusicherung erfordert Disziplin vom Programmierer: die Änderung der Eigenschaft darf nur durch die set-Methode erfolgen.
Der Denkfehler und das eigentliche roblem liegen IMO darin, dass du meine Erklärungen nicht verstanden oder wohl eher (Sorry wenn ich direkt bin) gar nicht wirklich gelesen hast.
Direkte und klare Worte sind schon in Ordnung. Aber trotzdem liegst du falsch: ich habe deinen Beitrag gelesen und verstanden. Möglicherweise anders als du es gemeint hast, aber sowas passiert schon mal.
Das stimmt so nicht. Man kann in einer überschreibenden Methode die überschriebene Methode aufrufen. Was in diesem Fall ja auch passiert. So wird neben der ursprünglichen Aktion noch eine weitere Aktion ausgeführt.
Denk zur Laufzeit in Objekten und NICHT in Klassen! Wenn du ein Objekt der abgeleiteten Klasse hast gibt es kein "aus der Superklasse" ---- es gibt keine Superklasse, es gibt nur ein Objekt der Subklasse - Punkt.
Ein Objekt ist immer ein Exemplar einer Klasse. Die Eigenschaften und Verhaltensweisen werden als Klasse definiert. Soweit klar?
Ein Exemplar (Objekt) einer abgeleiteten Klasse ist immer auch ein Exemplar der Basis-Klasse. Wenn du solch ein Objekt fragst, welcher Klasse es angehört wird es antworten, dass es der abgeleiteten Klasse angehört. Wenn du es aber fragst, ob es vielleicht auch der Basis-Klasse angehört, wird es das bestätigen. Das ist dir klar - oder?
Wenn du willst, dass man sie nicht überschreiben kann: Mach ein "final" davor.
Wenn das nicht geht, weil die Methode manchmal doch überschrieben sein soll, musst du nochmal überlegen: bei der gleichen Methode kann nicht manchmal die Methode der Unterklasse und manchmal die Methode der Basisklasse rauskommen.
Das sollte dann wohl eher 2 Methoden sein, denk ich mal.
Das mit dem "final" hat was für sich: wenn die Klasse das garantieren soll, darf das natürlich nicht überschrieben werden können.
In dem Sinne gebe ich dir Recht.
Das eigentliche Problem, um das es mir geht, ist aber: durch das überschreiben einer Methode ist die überschriebene Methode für die Basis-Klasse nicht mehr erreichbar. Auch nicht durch das voranstellen von "this". Schade eigentlich. Da in diesem Punkt bisher keiner widersprochen hat, markiere ich diesen Faden hier mal als erledigt.
Das eigentliche Problem, um das es mir geht, ist aber: durch das überschreiben einer Methode ist die überschriebene Methode für die Basis-Klasse nicht mehr erreichbar.
Das stimmt doch schlicht und ergreifend nicht. Natürlich ist sie für die Basis-Klasse erreichbar. Aber nicht für die Sub-Klasse. Und du hast ein Objekt der Sub-Klasse, deswegen wird auch die überschriebene Methode aufgerufen.
Wie gesagt, du denkst da wohl zu sehr in Klassen. Wenn du an Objekte denkst, dann müsste doch klar sein, dass ein Objekt vom Typ Sub-Klasse nur die überschriebene Methode sieht (und auch nur sehen darf!).
Ja - fast: die Eigenschaft ("name") ist in der abgeleiteten Klasse und darüber hinaus im gesamten Package sichtbar und damit änderbar. Wenn man die privatisiert sollte es funktionieren.
Wie gesagt, du denkst da wohl zu sehr in Klassen. Wenn du an Objekte denkst, dann müsste doch klar sein, dass ein Objekt vom Typ Sub-Klasse nur die überschriebene Methode sieht (und auch nur sehen darf!).
Nein - nicht ich denke zu sehr in Klassen, sondern du übersiehst den entscheidenden Punkt: ich würde gerne in der Basis-Klasse auf die in ihr definierte Methode zugreifen können. Das ist aber nicht möglich. Nicht mal durch das voranstellen von "this". Das sollte im Beispiel egentlich deutlich zu erkennen sein.
Nein - nicht ich denke zu sehr in Klassen, sondern du übersiehst den entscheidenden Punkt: ich würde gerne in der Basis-Klasse auf die in ihr definierte Methode zugreifen können. Das ist aber nicht möglich. Nicht mal durch das voranstellen von "this". Das sollte im Beispiel egentlich deutlich zu erkennen sein.
Du siehst, wir drehen uns im Kreis. Mit jedem Mal wird mir klarer, was du meinst. Und trotzdem bin ich mir jedesmal sicherer, dass das, was du tun willst, nicht funktionieren kann. Aus Gründen, die ich schon genannt habe.
Der Cast bringt dir übrigens garnichts an dieser Stelle. Damit stellst du nur sicher, dass dieses Objekt vom Typ BaseClass erbt und somit die Methode verwenden darf - ändert ja aber nichts daran, dass das Objekt tatsächlich ein DerivedClass ist und die Methode überschrieben wird. Oder ums mal "bildlich" auszudrücken, wie es Andi_CH mal gemacht hat in einem anderen Post: die Variable
Code:
derivedClass
"sieht"
Code:
method()
aus der BaseClass nichtmehr, weil es eine eigene Methode hat, die genauso heißt und dementsprechend die Methode überschreibt.
Nein - das stimmt nicht. Die Vererbung erfolgt mittels des Schlüsselwortes "extends". Der cast bewirkt, dass das Exemplar als Basis-Klasse behandelt wird. Ein Exemplar der abgeleiteten Klasse ist immer auch ein Exemplar der Basis-Klasse. Daher: Klassenbewusstsein ist wichtig.
Das ist der Kern des Problems: die überschriebene Methode ist nur für Exemplare der Basis-Klasse erreichbar - das ist klar. Hinweis: in einigen meiner vorigen Beiträge hatte ich angenommen, dass die Basis-Klasse abstrakt ist, aber nicht darauf hingewiesen - sorry.
Was ich gerne hätte ist folgendes: durch das voranstellen von "this" auf die überschriebene Methode zugreifen. Was aber nicht möglich ist. Andererseits ist es aber möglich, von der abgeleiteten Klasse aus - mittels "super" - auf die überschriebene Methode zuzugreifen. Nun ja - es ist eben wie es ist.
Nein - das stimmt nicht. Die Vererbung erfolgt mittels des Schlüsselwortes "extends". Der cast bewirkt, dass das Exemplar als Basis-Klasse behandelt wird.
AFAIK dient der Cast nur dem Compiler und hat keine Auswirkung auf die Laufzeit (es sei denn, man löst eine ClassCastException aus ).
Es lässt sich immer nur der Typ der Referenz ändern, aber nicht des Objekts.
Was ich gerne hätte ist folgendes: durch das voranstellen von "this" auf die überschriebene Methode zugreifen. Was aber nicht möglich ist. Andererseits ist es aber möglich, von der abgeleiteten Klasse aus - mittels "super" - auf die überschriebene Methode zuzugreifen. Nun ja - es ist eben wie es ist.
Java wählt für jedes Objekt die speziellste Methode, was ja auch sinnvoll ist. Hast du ein Objekt einer konkreten BaseClass, dann wird auch dessen Operation aufgerufen. In einer abgeleiteten Klasse dann natürlich die überschriebene (wozu denn sonst Methoden überschreiben?).
Und non-static Operationen werden sowieso immer auf this aufgerufen, wenn nichts anderes angegeben ist.
Nein - das stimmt nicht. Die Vererbung erfolgt mittels des Schlüsselwortes "extends". Der cast bewirkt, dass das Exemplar als Basis-Klasse behandelt wird. Ein Exemplar der abgeleiteten Klasse ist immer auch ein Exemplar der Basis-Klasse. Daher: Klassenbewusstsein ist wichtig.
Java wählt für jedes Objekt die speziellste Methode, was ja auch sinnvoll ist. Hast du ein Objekt einer konkreten BaseClass, dann wird auch dessen Operation aufgerufen. In einer abgeleiteten Klasse dann natürlich die überschriebene (wozu denn sonst Methoden überschreiben?).
Ja - aber ich will auch die überschriebene Methode aufrufen können. Beispielcode an dem man erkennen kann wie ich mir das vorstelle habe ich ja schon ein paarmal eingestellt.
Nein - das stimmt nicht. Die Vererbung erfolgt mittels des Schlüsselwortes "extends". Der cast bewirkt, dass das Exemplar als Basis-Klasse behandelt wird. Ein Exemplar der abgeleiteten Klasse ist immer auch ein Exemplar der Basis-Klasse. Daher: Klassenbewusstsein ist wichtig.
Ein Objekt ist immer nur Exemplar einer Klasse. Was du meinst, sind Typen. Ein Objekt hat i.d.R. viele Typen: Den Typ der eigenen Klasse, sämtlicher Oberklassen und aller implementierter Interfaces. Trotzdem gibt es nur eine konkrete Klasse, von der das Objekt erzeugt wurde (von synthetischen Proxys mal abgesehen).
Und der Cast ist wirklich nur eine Zusicherung für das Laufzeitsystem, dass ein Objekt einen bestimmten Typ hat. Eine Umwandlung oder Anweisung, wie irgendwelche Methoden aufzurufen sind, ist das nicht.
Und der Cast ist wirklich nur eine Zusicherung für das Laufzeitsystem, dass ein Objekt einen bestimmten Typ hat. Eine Umwandlung oder Anweisung, wie irgendwelche Methoden aufzurufen sind, ist das nicht.