Wie wählt Java aus, welche überladene Funktion aufgerufen werden soll?

8

Dies ist eine rein theoretische Frage.

Gegeben drei einfache Klassen:

%Vor%

Und eine Funktion, die auf diese Klassen angewendet werden soll:

%Vor%

Es scheint, dass der folgende Code:

%Vor%

kann berechtigterweise dazu führen, dass entweder BASE CALLED oder SUB CALLED gedruckt wird, da SubSub für beide ausgegeben werden kann. Wenn Sie die Sub-Version der Funktion entfernen, wird BASE CALLED tatsächlich gedruckt. Was tatsächlich passiert ist, dass "SUB CALLED" gedruckt wird. Dies scheint zu bedeuten, dass die Funktion, die aufgerufen wird, nicht von der Reihenfolge abhängt, in der die Funktionen definiert sind, da die Base-Version zuerst aufgerufen wurde.

Schaut sich Java nur die verschiedenen Versionen der Funktion an und wählt diejenige aus, die die kleinste Traversierung des Vererbungsstapels erfordert? Ist das standardisiert? Ist es in irgendeiner Dokumentation ausgeschrieben?

    
Claudiu 22.12.2008, 04:20
quelle

4 Antworten

8

Die formale Spezifikation finden Sie in Teil 15.12.2.5 der Java-Sprache Spezifikation (JLS) . Dank Generika ist das ziemlich kompliziert, deshalb sollten Sie sich dasselbe ansehen Abschnitt der ersten Ausgabe der JLS .

Es besagt grundsätzlich, dass der Compiler versucht, eine Version der Methode zu finden, in der alle Parameter einschließlich des Objekts, auf das die Methode angewendet wird, am spezifischsten sind. Wenn keine solche Methode existiert (z. B. wenn Sie method(Base, Sub) und method(Sub, Base) , aber nicht method(Sub, Sub) haben), schlägt die Kompilierung fehl.

Beachten Sie, dass die tatsächliche Wahl der Methode vom dynamischen Typ des Zielobjekts für Instanzmethoden abhängt, nicht jedoch für die Parameter. Ihr Beispiel würde auf Instanzebene immer noch dasselbe sein.

Sie sollten in der Lage sein, dem Compiler eine hilfreiche Hand zu geben, indem Sie den Typ von ss umwandeln oder neu deklarieren. Wenn der deklarierte Typ der Variablen genau mit einer Signatur übereinstimmt, dann ist auch für den Compiler und die Wartungsprogrammierer alles klar. Es spielt keine Rolle, ob Sie dann einen spezifischeren Typ zuweisen, solange der deklarierte Typ übereinstimmt.

    
Peter Becker 22.12.2008, 05:14
quelle
2

Soweit ich weiß, treffen Java und C ++ diese Entscheidung zum Zeitpunkt der Kompilierung (da es sich um statische Funktionen handelt, die nicht dynamisch verteilt werden können), basierend auf dem spezifischsten Abgleich, den sie vornehmen können. Wenn Ihr statischer Typ SubSub ist und Sie eine Überladung haben, die SubSub übernimmt, ist dies der, der aufgerufen wird. Ich bin ziemlich sicher, dass es in beiden Standards ist.

Wenn Sie einen Verweis oder einen Zeiger auf Base haben, selbst wenn er einen Sub- oder einen SubSub enthält, stimmen Sie mit der Version überein, die eine Base benötigt, da dies zur Kompilierungszeit die einzige Sicherheit des Compilers ist.

    
Uri 22.12.2008 04:31
quelle
0

Wenn Sie statische Methoden überladen haben, ruft sie die Methode auf, die sofort in der Klasse definiert wird, die die Methode aufruft. Wenn jedoch in der aufrufenden Klasse keine Methode definiert ist, wird die Methode aufgerufen, die von ihrer unmittelbaren übergeordneten Klasse geerbt wurde.

In Ihrem Fall gibt es zwei überladene Methoden, die SubSub als Parameter akzeptieren können. Der Compiler sucht nach der spezifischsten Übereinstimmung und geht darauf zu. Aber die spezifischste Übereinstimmung ist im Allgemeinen die niedrigste in der Typhierarchie.

BEARBEITET

Die widersprüchliche Aussage wurde entfernt. Zwei Methoden in Klassen, die sich auf der gleichen Hierarchieebene befinden, dürfen nicht im mehrdeutigen Status sein, damit der Compiler sie auswählen kann. Diese Mehrdeutigkeit ist nur bei Mehrfachvererbung möglich.

    
Tushu 22.12.2008 04:51
quelle
0

Java bindet Methoden dynamisch (zur Laufzeit, abhängig vom Objektinstanztyp, nicht vom Referenztyp), aber nur im Kontext einer Methodensignatur. Java bindet die Methodensignatur statisch (zur Kompilierungszeit).
Mit anderen Worten entscheidet Java, welche Methode (Signatur) in der Kompilierzeit aufgerufen werden soll (statisch - referenzbasiert - überladen). In Runtime nimmt Java diese Signatur an, sucht das richtige Objekt in der Objekttyphierarchie und führt diese Methode für dieses dynamisch verknüpfte Objekt aus.

Überladen - & gt; Was (Methodensignatur zum Zeitpunkt der Kompilierung)
Überschreiben - & gt; von wo (Objekt in der Typhierarchie zur Laufzeit)

    
mombip 19.07.2014 21:12
quelle