Polymorphie Dynamischer oder Statischer Typ für Methodenparameter

LutzB

Mitglied
Hallo,

Ich habe mal 2 Fragen, zum Thema dynamischer und statischer Typ.

1. Zum ersten eine grundsätzliche Frage: Methodenparameter selbst werden wie Attribute behandelt und entsprechend ihres statischen Typs ausgewertet? Ich habe dazu nirgends eine konkrete Aussage gefunden, und mir das nur anhand der Ausgabe des unten stehenden Programms erschlossen:
Java:
class Weg {};
class Trampelpfad extends Weg {
    enum Material{Matsch, Stein, Kies};
    }

class Sportler {
    void sportTreiben (Weg weg) {
        System.out.println ("1");
    }
    void gemeinsamSportTreiben (Weg pfad, Laeufer laeufer) {
        System.out.println ("2");
    }
}

class Laeufer extends Sportler {
    void gemeinsamSportTreiben (Trampelpfad weg, Sportler nachbar) {
        System.out.println("3");
    }
}

class Sprinter extends Laeufer {
    void sportTreiben (Trampelpfad weg) {
        System.out.println ("4");
    }
}


public class VonSportlern {
    public static void main (String [] args) {
        Sprinter sprinter = new Sprinter ();
        Laeufer laeufer = sprinter;
       
        Trampelpfad pfad = new Trampelpfad ();
        Weg weg = pfad;
       
       
        laeufer.gemeinsamSportTreiben(weg,laeufer);
        laeufer.sportTreiben(pfad);
    }
}


Die Ausgabe für den Methodenaufruf in Zeile 37 lautet 2, damit ist von den überladenen Methoden diejenige zum Einsatz gekommen, deren formale Parameter den statischen Typen der aktuellen Parameter entspricht. Die Methode deren formale Parameter den dynamischen Typen der aktuellen Parameter entsprechen wurde nicht verwendet.

2. Wieso erhalte ich mit dem Methodenaufruf laeufer.sportTreiben(pfad) in Zeile 38 die Ausgabe "1" und nicht die Ausgabe "4"?

Der dynamische Typ von laeufer ist Sprinter, damit stehen die in Sprinter deklarierten Methoden zur Verfügung. Im most-specific-Ansatz müsste damit also zwischen den Methoden sprotTreiben der Klasse Sprinter und der der Klasse Sportler "ausgewählt werden". Der statische Typ von Pfad ist Trampelfpfad (wegen Trampelfpfad pfad = new Trampelpfad()😉 und bleibt es auch trotz der Zuweisung in der Zeile darunter, oder? Denn diese Zuweisung dürfte doch nur den dynamischen Typen von weg" ändern?

Wenn der statische Typ von Pfad Trampelpfad ist, sollte doch die Methode sportTreiben der Klasse Sprinter die speziellere sein, da Pfad ( = Trampelpfad) ein Subtyp von Weg ist. Wieso wird diese Methode dann also offensichtlich nicht ausgeführt?



Wäre super, wenn mir jemand helfen könnte!

Vielen Dank schon mal im Voraus!

Lutz
 
lauf mal per Debugger drüber und schau Dir an, WO der Code genau langläuft!
Damit löst sich das Problem, *warum* er "da lang läuft" nicht. Wo er lang läuft, weiß er schon...

Der dynamische Typ von laeufer ist Sprinter, damit stehen die in Sprinter deklarierten Methoden zur Verfügung.
Zum Aufrufen stehen die in Laeufer deklarierten Methoden zur Verfügung.
Zusätzliche in Sprinter deklarierte sind ja statisch nicht bekannt, erst dynamisch.

Im most-specific-Ansatz müsste damit also zwischen den Methoden sprotTreiben der Klasse Sprinter und der der Klasse Sportler "ausgewählt werden".
Aus obigem Grund eben nicht, nur aus Laeufer (und damit auch Sportler).

Der statische Typ von Pfad ist Trampelfpfad (wegen Trampelfpfad pfad = new Trampelpfad()😉 und bleibt es auch trotz der Zuweisung in der Zeile darunter, oder? Denn diese Zuweisung dürfte doch nur den dynamischen Typen von weg" ändern?
Der dynamische Typ ist immer der gleiche und ändert sich nicht.
Der statische Typ von pfad ist Trampelfpfad, da als solches deklariert.
Der statische Typ von weg ist aber eben deshalb Weg, erst der dynamische Typ ist Trampelfpfad.

Wenn der statische Typ von Pfad Trampelpfad ist, sollte doch die Methode sportTreiben der Klasse Sprinter die speziellere sein, da Pfad ( = Trampelpfad) ein Subtyp von Weg ist. Wieso wird diese Methode dann also offensichtlich nicht ausgeführt?
Die statischen Typen sind in dem Fall allerdings eben Laeufer und Weg 😉
 
2. Wieso erhalte ich mit dem Methodenaufruf laeufer.sportTreiben(pfad) in Zeile 38 die Ausgabe "1" und nicht die Ausgabe "4"?
Beim Aufruf laeufer.sportTreiben(pfad); ist zunächst der statische Typ von laeufer (also Laeufer) dahingehend maßgeblich, dass nur Methoden in Betracht kommen, die garantiert für jeden Laeufer-Subtypen existieren. Der Compiler weiß nicht, dass es hier gerade um einen Sprinter geht und nicht etwa um einen Langstreckler, für den es vielleicht gar keine Methode sportTreiben(Trampelpfad); gibt.
Die Auswahl der passenden Methodensignatur orientiert sich also am statischen Typ, demzufolge wird sportTreiben(Weg); selektiert. Für die Auswahl der konkreten Implementierung dieser Signatur ist aber der dynamische Typ maßgeblich. Falls Sprinter beispielsweise zusätzlich eine Methode sportTreiben(Weg) enthalten würde, würde die aufgerufen werden.
 
Vielen Dank für eure Antworten. Da muss ich jetzt erst mal ne Runde drüber nachdenken und es sacken lassen. Dachte eigentlich, ich hätte das Thema relativ gut verstanden, die Meinung muss ich wohl erst mal revidieren. 😵
 
Die Auswahl der passenden Methodensignatur orientiert sich also am statischen Typ, demzufolge wird sportTreiben(Weg); selektiert. Für die Auswahl der konkreten Implementierung dieser Signatur ist aber der dynamische Typ maßgeblich. Falls Sprinter beispielsweise zusätzlich eine Methode sportTreiben(Weg) enthalten würde, würde die aufgerufen werden.

Zum Sichergehen, dass ich es wirklich verstanden habe: Die dynamische Bindung ist also nur für überschriebene Methoden relevant, nicht für in den Subtypen "zusätzlich" hinzugefügte Methoden?
 
Der dynamische Typ ist immer der gleiche und ändert sich nicht.
Der statische Typ von pfad ist Trampelfpfad, da als solches deklariert.
Der statische Typ von weg ist aber eben deshalb Weg, erst der dynamische Typ ist Trampelfpfad.

Die statischen Typen sind in dem Fall allerdings eben Laeufer und Weg 😉

Wirklich sorry, für die dummen Fragen, aber ich bin jetzt schwer verwirrt: Der statische Typ von pfad nach der Zuweisung
Java:
  Trampelpfad pfad = new Trampelpfad ();
        Weg weg = pfad;
ist dann Weg?
Also
Java:
 Trampelpfad pfad = new Trampelpfad ();
Referenztyp pfad:
statischer Typ - Trampelpfad;
dynamischer Typ - Trampelpfad​

Java:
  Weg weg = pfad;
Referenztyp weg:
statischer Typ - Weg;
dynamischer Typ - Trampelpfad
UND gleichzeitig ändert sich der statische Typ für den Referenztyp pfad von Trampelpfad zu Weg?

Anders verstehe ich sonst nicht, wie der statische Typ von pfad dann wie du sagst, weg sein kann.
Die statischen Typen sind in dem Fall allerdings eben Laeufer und Weg 😉
Ich dachte der statische Typ einer Referenz bleibt immer gleich, nur der dynamische Typ lässt sich durch Zuweisung verändern?
 
Wirklich sorry, für die dummen Fragen, aber ich bin jetzt schwer verwirrt: Der statische Typ von pfad nach der Zuweisung
Java:
  Trampelpfad pfad = new Trampelpfad ();
        Weg weg = pfad;
ist dann Weg?
Also
Java:
 Trampelpfad pfad = new Trampelpfad ();
Referenztyp pfad:
statischer Typ - Trampelpfad;
dynamischer Typ - Trampelpfad​

Java:
  Weg weg = pfad;
Referenztyp weg:
statischer Typ - Weg;
dynamischer Typ - Trampelpfad
UND gleichzeitig ändert sich der statische Typ für den Referenztyp pfad von Trampelpfad zu Weg?

Anders verstehe ich sonst nicht, wie der statische Typ von pfad dann wie du sagst, weg sein kann.

Ich dachte der statische Typ einer Referenz bleibt immer gleich, nur der dynamische Typ lässt sich durch Zuweisung verändern?

Der statische Typ von pfad ist immer Trampelpfad und lässt sich auch durch nichts ändern - der statische Typ ist dabei der Typ, als es deklariert wurde. Genauso ist der statische Typ von weg immer Weg.

Der dynamische Typ wird durch die Zuweisung bestimmt und ist in beiden Fällen Trampelpfad.
 

Zurück
Oben