Java Methoden aus anderen Unterklassen aufrufen (Greenfoot)?
Hey, habe eine kurze Frage über Vererbungen und Klassen. Im Internet konnte ich darauf bisher keine Antwort finden.
Also erstmal die wichtigsten Punkte zusammengefasst:
Ich habe 2 Unterklassen die von der Actor-Klasse abstammen, die Wiederum Unterklassen besitzen (wie eine Gabel).
Das würde dann wie folgt aussehen:
PlayerRabbit erbt von Rabbit, erbt von Actor und
Carrot, PickAxe... erbt von PickableObjects erbt von Actor.
Ich würde nun gerne von PlayerRabbit aus eine Methode von z.B. PickAxe aufrufen. Hierfür hätte ich folgenden Code geschrieben:
________________________
PickableObjects[] objs = getRabbitWorld().getObjectArrayAt(getX(), getY(), PickableObjects.class);
objs[0].doSomething();
________________________
Ich würde dann ein Objekt "vom Typ PickableObjects", also nur Carnot, PickAxe, Banana... aufnehmen, in einer zwischenvariable speichern und dann auf die Methode doSomething() aufrufen.
Das Problem hierbei ist nun jedoch, dass er nur die Methode aus der Klasse PickableObjects anspricht.
(Wenn ich "public void doSomething" in der Klasse PickableObjects definiere passiert etwas, wenn ich es hingegen nur in den Carnot, PickAxe... definiere erkennt er die Methode nicht)
Würde mich über jede Hilfe freuen! Danke :9
PS: Ja, alle meine Methoden sind Public und ja, die Objekte werden auch direkt angesprochen. (Bei dem Befehl getRabbitWorld().removeObject(objs[0]); kann ich das Objekt zum Beispiel entfernen)
2 Antworten
Da du die Objekte in einem PickableObjects-Array speicherst werden die Objekte auch nur als PickableObjects behandelt, hier wird implizit ein Upcast durchgeführt wobei die zusätzlichen Funktionalitäten der Unterklasse verloren gehen.
Du kannst aber zur Laufzeit wieder einen Downcast durchführen wenn du dir sicher bist dass es sich bei dem Objekt um ein Objekt der speziellen Unterklasse handelt um die Funktionalität der Unterklasse wieder herzustellen.
Durch einen Downcast versicherst du dem Compiler (und dem Programm) dass es sich bei dem Objekt auch ganz sicher um das Objekt der Unterklasse handelt.
Beispiel:
Ball konkreterBall = new Ball();
PickableObject x = konkreterBall; -> Funktioniert da jeder Ball auch ein PickableObject ist!
konkreterBall.methodeDieNurDieBallklasseKann(); -> Klappt!
x.methodeDieNurDieBallklasseKann(); -> Fehler da der Ball für das Programm gerade wie ein PickableObject aussieht!
((Ball)x).methodeDieNurDieBallklasseKann(); -> Hier wird durch einen Downcast dem Programm versichert dass es sich bei x um einen Ball handel, klappt also wieder!
Hier mit Downcasts herumzufuhrwerken ist eher keine gute Idee. Code dieser Sorte ist zwar manchmal unvermeidlich, aber für derartig einfache Programme ein deutliches Alarmzeichen für schlechten Entwurf:
Superclass bla = ...
if(bla instanceof Subclass1) {
((Subclass1)bla).doSomething();
} else if (bla instanceof Subclass2) ...
Wenn doSomething() für jedes PickableObject sinnvoll ist, sollte es auch Teil von dessen Interface sein. Jede Subklasse kann es dann nach Bedarf passend implementieren, zur Laufzeit wird der richtige Code ausgeführt.
Wenn ich "public void doSomething" in der Klasse PickableObjects definiere passiert etwas, wenn ich es hingegen nur in den Carnot, PickAxe... definiere erkennt er die Methode nicht
Das ist auch logisch so. Wenn doSomething() für alle PickableObjects sinnvoll ist, dann definiere es da drin (ggf. leer oder abstract). In den Subklassen (Apple, Ball) wird es dann implementiert bzw. überschrieben.
jup, nur möchte ich das die "doSomething()" Methode sich selbst zurückgibt.
z.B. soll er nach dem Aufruf dieser Methode dem Spieler 10 Leben zurückgeben, oder sich mit einer bestimmten Wahrscheinlichkeit in etwas anderes verwandeln. um eben dieses "return this" zurückzugeben und das ganze ordentlich zu halten würde ich die Methode gerne in der jeweiligen Klasse definieren.
LG und danke!
Ich bin nicht sicher, ob ich dich verstehe.
Das doSomething() soll also ein PickableObject zurückgeben, ggf. auch sich selbst? Das kann es ja ohnehin.
Du musst grob gesagt drei Dinge unterscheiden: Interface, Implementierung, und Daten (des Objekts zur Laufzeit).
Deine Subklassen erben zwingend das Interface der Superklasse. Sie erben auch die Implementierungen, können diese aber überschreiben (also durch eigene ersetzen). Zur Laufzeit werden natürlich immer die Daten des jeweiligen Objekts genommen (wenn wir jetzt mal keine statischen Instanzvariablen verwenden).
Wenn sich hinter einem PickableObject also tatsächlich zur Laufzeit eine PickAxe versteckt, wird automatisch deren Implementierung von doSomething() aufgerufen und natürlich mit den Daten des jeweiligen PickAxe-Objekts. Der Aufrufer muss sich nicht darum kümmern.
Okay, Danke erstmal für deine Antwort! Könntest du mir vielleicht noch kurz sagen wie man diesen "umgedrehten super-Befehl" benutzt?
LG und Danke!